09.14 毀屍滅跡!一次服務器被入侵的血淚教訓

毀屍滅跡!一次服務器被入侵的血淚教訓

前言

筆者的工作之一是管理100臺左右的服務器,要保證其24小時處於正常working模式。誰知天有不測風雲,前幾天筆者管理的服務器大範圍被植入發送DDOS攻擊的程序,每天凌晨發動攻擊。不幸中的萬幸是我們主動發現問題,要是被老闆先發現,估計要準備去人才市場了。

服務器安全策略

筆者管理的主機均為centOS,全部運行在公網上,對外提供服務。第一道安全策略是hosts策略,只允許從指定的主機訪問公網服務器。

#

# hosts.allow This file contains access rules which are used to

# allow or deny connections to network services that

# either use the tcp_wrappers library or that have been

# started through a tcp_wrappers-enabled xinetd.

#

# See 'man 5 hosts_options' and 'man 5 hosts_access'

# for information on rule syntax.

# See 'man tcpd' for information on tcp_wrappers

#

sshd:xxx.xxx.xxx.xxx/255.255.255.255

編輯/etc/hosts.allow,設置“白名單”(即允許SSH登錄本機的IP地址),掩碼設置為255.255.255.255表示為1臺主機。

#

# hosts.deny This file contains access rules which are used to

# deny connections to network services that either use

# the tcp_wrappers library or that have been

# started through a tcp_wrappers-enabled xinetd.

#

# The rules in this file can also be set up in

# /etc/hosts.allow with a 'deny' option instead.

#

# See 'man 5 hosts_options' and 'man 5 hosts_access'

# for information on rule syntax.

# See 'man tcpd' for information on tcp_wrappers

#

sshd:all

編輯/etc/hosts.deny,設置“黑名單”,掩碼設置為255.255.255.255表示為1臺主機。sshd表示使用ssh協議,all表示所有IP均不允許。hosts.allow的優先級高於hosts.deny。這是第一層防護。

第二道安全策略是修改SSH默認端口(SSH默認使用TCP協議22端口,如果你對TCP協議不太瞭解,請參考我的另一篇文章: 。關鍵配置如下:

Port 22222

#Port 22

配置文件位置是etc/ssh/sshd_config。#號代表不生效,本例中將SSH端口改為了22222(理論上你可以在0-65535範圍任意選擇端口號,但不建議選擇1024以下的端口,這些端口為系統保留端口)。

第三層防護是防火牆,只允許指定的IP連接SSH端口。

#只允許IP地址為x.x.x.x的設備訪問本機22222端口,限定TCP

/sbin/iptables -A INPUT -s x.x.x.x -p tcp --dport 22222 -j ACCEPT

#拒絕所有其它地址訪問本機22222端口。

/sbin/iptables -A INPUT -p tcp --dport 22222 -j DROP

防火牆也是按從上到下的順序執行,滿足條件後就不再往下執行,類似於程序中的break;

入侵分析及處理

所有主機並沒有提供web服務,排除了web注入的可能性。想要植入程序,只有登錄主機才可能。入侵者就是在我自建的三層防護下完成了植入,並且刪除掉了登錄日誌(/var/log/secure、/var/log/message)、清掉了登錄接入記錄(/var/log/wtmp和//var/run/wtmp、/var/log/lastlog),甚至連歷史命令記錄(~/.bash_history)也全部刪除了,可謂“毀屍來跡”!我連入侵者做了什麼操作都不知道。

首要的工作當然是清理植入程序。通過netstat -napt | more命令,查詢主機所有已開啟的偵聽端口,未發現異常。


毀屍滅跡!一次服務器被入侵的血淚教訓


image.png

使用ps ax命令列出當前系統運行的所有進程,發現了植入程序。(因為當時太著急清除,忘記截取病毒進程照片。但我想說的是如何根據進程找到其程序目錄。假設我們要查的進程如下圖


毀屍滅跡!一次服務器被入侵的血淚教訓


image.png

這是一個運行中的進程,進程號是30199,從上面我們得不到程序的安裝路徑。我們可以通過如下方法查詢其安裝路徑

$ cd /proc/30199

$ ll

毀屍滅跡!一次服務器被入侵的血淚教訓


image.png

圖中標註的就是進程的安裝路徑,我們先通過kill命令殺掉進程,然後刪除整個程序安裝目錄。其次,使用crontab -l查看是否有輪詢執行的異常腳本,檢查cron的執行內容,最後檢查啟動服務chkconfig --list檢查是否有異常程序加入了服務,/etc/rc.local等啟動會執行的文件也要進行檢查,防止攻擊程序自動啟動。到這裡,植入的程序算是清除了。但是很奇怪,我的防火牆策略、hosts策略都沒有被動過痕跡,也保持著開啟狀態,入侵者是怎麼進來的呢?

經過排查,我發現了兩點可疑情況,一是部分未被植入的服務器都是最近才新上線,二是我管理的設備分部在天南地北,為何命中如此精準,絕大部分都中了招。

我開始懷疑是“內鬼”所為,因為設備列表只有我和合作方才有,新加的服務器還沒來得及告訴相關所有人員。

不管如何推測,當前最重要的一件事就是安全加固。

提升系統安全性

  • 思路:
  1. 建立日誌服務器,將所有主機的登錄日誌和歷史命令日誌監控起來,併發送給日誌服務器,防止入侵者銷燬記錄。
  2. 所有主機關閉密碼登錄,全部改為證書登錄方式,並且只能通過指定主機才能夠登錄服務器。

有了思路,我們開始實現。

建立日誌系統

  • 日誌發送端

我們的第一個目標是將用戶輸入過的歷史命令傳輸到日誌服務器保存。歷史命令保存在~/.bash_history文件中,一般我們只需要提出root用戶的歷史命令,即/root/.bash_history,我們想實時的將主機上輸入的的命令傳到日誌服務器。先要做兩個設置。

#不同登錄會話共享history歷史命令庫

shopt -s histappend

#將內存中的命令寫入文件,而不是當前用戶登出後再寫入。

PROMPT_COMMAND="history -a"

/root/.bash_profile(用戶登錄系統會讀取該配置文件的設置)

默認情況下,同時幾個用戶登錄同一臺主機,他們只會讀取登錄前的歷史記錄,但彼此之間錄入的命令相互是看不到的,shopt -s histappend就是讓同時登錄的用戶共享一個歷史命令庫。還有一個默認設置,當前用戶輸入的命令並不會直接寫入到歷史命令日誌文件,而要在其登出時才寫入,這就不符合我們實時傳輸命令信息的要求,通過PROMPT_COMMAND="history -a",將其設置為輸入命令即寫入到本機的歷史命令日誌文件(/root/.bash_history)中。

設定好後,我們開始配置日誌客戶端。

centOS默認採用rsyslog程序管理日誌,我們通過一些配置就能夠使其滿足我們的要求。rsyslog的配置文件存放在/etc/rsyslog.conf中。

#默認加載模塊,提供本地系統日誌功能。

$ModLoad imuxsock

#默認加載模塊,日誌核心模塊。

$ModLoad imklog

#加載imfile模塊,Text File Input Module(文本文件輸入模塊),可以將任何的標準輸入轉換為syslog消息。需要開啟此模塊,後續會詳細講解為何要開啟此模塊。

$ModLoad imfile

#模認日誌格式

$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

$IncludeConfig /etc/rsyslog.d/*.conf

$IncludeConfig /etc/rsyslog.d/*.conf

#表明要監控的日誌文件為/root/.bash_history,歷史命令都會記錄在此文件中。(手工監控的原因就是因為syslog不會處理history歷史命令,前面開啟imfile模塊就是為了手工監控此文件)

$InputFileName /root/.bash_history

#給此監控操作打一個tag(標誌),用於日誌接收端根據tag分別處理。

$InputFileTag historyCommand

#記錄指定監控日誌文件的處理狀態,比如/root/.bash_history文件已經處理了多少行等狀態信息,可以自定義名稱。根據筆者觀察,文件默認生成在/目錄下。

$InputFileStateFile state_product_cache-Statistic

#對指定監控文件進行輪詢訪問的時間間隔,這是的10是以秒為單位,每隔10秒以確認所監控的文件是否有新數據產生。

$InputFilePollInterval 10

#表示處理多少行後更新狀態文件,建議改大一點,寫狀態文件需要消耗系統資源。

$InputFilePersistStateInterval 25000

#設置syslog消息類型,以local開始表示自定義類型,本例為local5,用於日誌接收端分類處理。

$InputFileFacility local5

#定義日誌的報警級別,此處定義為info級(有info,notice,warning等等)

$InputFileSeverity info

#設定監控操作是否生效,必選項

$InputRunFileMonitor

#第2個要監控的文件

$InputFileName /var/log/secure

$InputFileTag sshLogin

$InputFileStateFile state_product_cache-sshLogin

$InputFilePollInterval 10

$InputFilePersistStateInterval 25000

$InputFileFacility local5

$InputFileSeverity info

$InputRunFileMonitor

#表示監控的類型和級別,符合條件的寫入到/var/log/message

*.info;mail.none;authpriv.none;cron.none;local5.none /var/log/messages

#表示類型為authpriv(登錄認證信息)的,級別為所有的消息寫入/var/log/secure

authpriv.* /var/log/secure

mail.* -/var/log/maillog

cron.* /var/log/cron

*.emerg *

uucp,news.crit /var/log/spooler

local7.* /var/log/boot.log

//loca5是我們的自定義類型,@@表示使用tcp協議將類型為loca5的所有級別的日誌消息發送到192.168.100.100的100514端口上。

local5.* @@192.168.100.100:10514

日誌發送端主機/etc/rsyslog.conf完整配置

以上配置的目的就是為了監控2個日誌文件(/root/.bash_history和/var/log/secure),一旦文件內容發生了更新,就會將日誌轉發到192.168.100.100上,由100服務器處理日誌消息,注意更新配置文件後記得重啟rsyslog服務,命令是service rsyslogd restart,下面我們看看日誌接收端的配置。

$ModLoad imuxsock

$ModLoad imklog

#開啟tcp監聽模塊,用於監聽發送端主機發送的日誌消息。

$ModLoad imtcp

#監聽端口為TCP 10514端口,端口可自定義,不和現有監聽端口衝突即可。

$InputTCPServerRun 10514

$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

$IncludeConfig /etc/rsyslog.d/*.conf

#創建模板,定義寫入日誌消息格式。#template是關鍵字,historyFormat為自定義模板名稱,%timegenerated%是系統內部屬性變量,表示產生消息的時間,其它幾個分別是消息發送主機,主機名,發送的消息內容(文字消息)

$template historyFormat,"%timegenerated% %FROMHOST-IP%(%HOSTNAME%) : :%msg%\\n"

$template sshLoginFormat,"%timegenerated% %FROMHOST-IP%(%HOSTNAME%) : %syslogtag%:%msg%\\n"

#syslogtag是syslog內部屬性變量,還記得在發送端我們配置了2個tag嗎?這裡派上用場了,一個是`historyCommand`,另一個是`sshLogin`。/root/historyTag.log表示日誌記錄位置,historyFormat使用上面定義的消息格式。

:syslogtag, startswith, "historyCommand" /root/historyTag.log;historyFormat

:syslogtag, startswith, "sshLogin" /root/sshlogin.log;sshLoginFormat

*.info;mail.none;authpriv.none;cron.none;local5.none /var/log/messages

authpriv.*;local5.none /var/log/secure

mail.* -/var/log/maillog

cron.* /var/log/cron

*.emerg *

uucp,news.crit /var/log/spooler

local7.* /var/log/boot.log

日誌接收端主機/etc/rsyslog.conf完整配置

關鍵配置其實就是模板定義,及後續的消息處理。設定好配置,記得重啟rsyslog服務。在客戶機上輸入一條命令,然後在服務器上查看是否能夠接收到客戶機輸入的信息。


毀屍滅跡!一次服務器被入侵的血淚教訓


image.png

在客戶機上隨意執行一條命令。


毀屍滅跡!一次服務器被入侵的血淚教訓


image.png

我們看到在客戶機上輸入的命令已經傳送到服務器並保存在了服務器上。

再來看看登錄信息。

毀屍滅跡!一次服務器被入侵的血淚教訓

在客戶機上的登錄信息在其登入時就已經發送到了日誌服務器上。

第一個目標總算基本完成了,可能有一點點複雜,但也就是操作幾個配置文件的事,以上的配置都是經過了我實機測試,是能夠正常工作的。

接下來的問題是如何批量部署到客戶機上,如果您看過我之前的文章( ),一定會選擇類似Ansible的批量執行作業的軟件。這裡我們使用Ansible來進行日誌發送端的部署工作。

首先將整理好的rsyslog.conf文件存放在安裝了Ansible的主機上。

#將本機rsyslog.conf拷貝到目標主機群(centos7)每一臺機器,並存放到/etc/目錄下,文件名同樣為rsyslog.conf。force的意思是如果目標文件已經存在,強制覆蓋。

ansible centos7 -m copy -a "class="lazy" data-original=/root/rsyslog.conf dest=/etc/rsyslog.conf force=yes"

#寫入shopt -s histappend配置到/root/.bash_profile文件中。

ansible centos7 -m shell -a "echo 'shopt -s histappend' >> /root/.bash_profile"

#寫入PROMPT_COMMAND=\\"history -a\\"到/root/.bash_profile文件中。

ansible centos7 -m shell -a "echo 'PROMPT_COMMAND=\\"history -a\\"' >> /root/.bash_profile"

#重啟rsyslog服務(centos 7使用該命令,如果為centos 6使用service rsyslog restart

ansible centos7 -m shell -a "systemctl restart rsyslog"

通過以上幾行命令,執行順利的話,所有日誌發送端的配置已經完成並生效了。

第二個目標由於篇幅關係,以後有機會再和大家分享。通過此次教訓讓我明白了安全防護的重要性,安全問題再怎麼小心也不為過,希望通過我的教訓引起大家對安全的重視。

補充聲明,本人其實不是安全專業的從業者,只是自己在實際運維中摸索出來的經驗,只是希望寫出來和大家一起交流、探討。水平有限,請大家見諒。

更多文章請關注我的公 眾 號:Ted的技術樂園


分享到:


相關文章: