[轉貼]Grub2被曝登陸驗證繞過0Day,影響眾多Linux版本

近日,研究人員發現了一個Grub2的漏洞,版本1.98(2009年發布)到2.02(2015年發布)均受影​​響。本地用戶能夠通過這個漏洞繞過任何形式的認證(明文密碼或者哈希密碼),使得攻擊者進而可以獲得電腦的控制權限。而大部分的linux系統都將Grub2作為開機引導程序,包括一些嵌入式系統。因此將有不計其數的設備受到此漏洞的威脅。
如下圖所示,我們成功的在Debian 7.5 QEMU下利用這個漏洞獲得了Grub rescue shell。

快速判斷你的系統是否有該漏洞?

想要快速判斷你的系統是否有這個漏洞,只需在grub出現輸入用戶名的界面時,連續按28次Backspace(退格鍵),如果系統重啟或者返回rescue shell ,那麼你的grub就會受到該漏洞影響。

影響

成功利用此漏洞的攻擊者可以得到Grub rescue shell,Grub rescue是一個權限非常高的shell,通過這個漏洞可以做到以下事情:
1.權限提升:攻擊者在沒有有效的用戶名密碼的情況下即可獲得grub控制台的所有權限。
2.信息洩露:攻擊者可以通過加載一個定制的內核和initramfs(比如從USB加載),從而獲得一個更便利的環境,拷貝竊取整個硬盤的數據或者往系統里安裝一個rootkit。
3.拒絕服務:攻擊者能夠摧毀任何數據包括grub自身,即使硬盤是加密的數據也可以被覆蓋,從而造成DOS(系統無法使用)。

細節

這個漏洞從1.98(2009)版本就存在grub的代碼中了,b391bdb2f2c5ccf29da66cecdbfb7566656a704d是這個漏洞的提交編號,問題就存在於grub_password_get()函數中。
其中有兩個函數都存在整數下溢問題grub_username_get()和grub_password_get()。它們分別存在於grub-core/normal/auth.c和lib/crypto.c文件中。這兩個函數除了對printf()的調用在其他地方都是一樣的,就像下面所示的grub_username_get()那樣。本文中的POC是通過利用grub_username_get()中的漏洞獲取Grub rescue shell的。
以下是grub_username_get()函數中的漏洞細節代碼:

grub_username_get()函數代碼

這個問題是由於自減變量cur_len沒有做範圍校驗導致的。

利用(POC)

這段代碼中,對cur_len變量的使用存在兩個問題off-by-twoOut of bounds overwrite(代碼中後面兩個註釋)。前面那個錯誤註釋點,在用於存儲用戶名的緩衝區中會有兩個字節的超長,但是這裡沒有辦法利用,被覆蓋的內存是用於填充的。
後面那個錯誤註釋點(// Out of bounds overwrite 這裡)比較有意思,因為這句代碼允許我們用0×00去覆蓋用於存儲用戶名緩存的內存。這是因為grub_memset()函數會嘗試將用戶名緩衝區未使用的字節設置成0×00。為了達到這個目的,這段代碼會計算出第一個未使用的字節地址和需要被填充為0×00的緩衝區的大小。這兩個計算的結果會作為參數傳遞給grub_memset()函數:
grub_memset (buf + cur_len, 0, buf_size - cur_len);舉個例子,當在用戶名中輸入“root”時,cur_len的值為5,grub_memset()函數會將用戶名緩衝區的第5到1024字節(用戶名和密碼的緩衝區長度為1024字節)清空(設置為0×00)。這樣寫代碼其健壯性是很好的。例如,如果輸入的用戶名被存儲在乾淨的1024-byte數組中,就可以直接將整個1024-byte內存與有效的用戶名進行比較,而不是去比較兩個字符串。這樣能夠防禦一些short of side-channels攻擊,比如timing attacks(比如第一次輸入username為aaaaaaaa,然後接著又輸入bbbb,這樣編碼就可以避免出現第二次結果為bbbb[0x00]aaa的情況)。

最簡單快速的驗證這個內存覆蓋越界的方法就是不停的按backspace (退格鍵)讓cur_len變量下溢,達到一個非常大的值,這個值馬上會被用來計算待清空空間的起始地址。
memset destination address = buf + cur_len通過這個點,由於用戶名緩衝區地址的值超出了32位變量能夠存儲的範圍,第二次緩衝區溢出被觸發。因此,我們要通過精心構造第一次下溢與第二次緩衝區溢出來計算grub_memset()函數將要使用的目的地址:
cur_len--; // Integer Underflowgrub_memset (buf + cur_len, 0, buf_size - cur_len); // Integer Overflow下面的這個例子可以幫助你們去理解我們是如何利用這個漏洞的。假設用戶名緩衝區的起始地址為0x7f674,然後攻擊者按一次退格鍵(下溢值為0xFFFFFFFF),那麼memset就是下面這樣的:
grub_memset (0x7f673, 0, 1025);第一個參數:(buf+cur_len) = (0x7f674+0xFFFFFFFF)=(0x7f674-1) = 0x7f673;第二個參數:用來覆蓋內存的常量,這裡是0;第三個參數是要覆蓋的大小:(buf_size-cur_len)=(1024-(-1))=1025。結果就是,整個用戶名的緩衝區空間(1024)外加前面的一個字節全都被0×00覆蓋。
按下的退格鍵的次數,就是用戶名緩衝區之前填充的0×00的數量。
現在,我們已經能夠覆蓋用戶名緩衝區的任意數量的字節。接下來需要去找0×00覆蓋到並且可以用來實現惡意代碼執行的內存地址。在棧幀中進行尋找,可以很快發現grub_memset()函數的返回地址能夠被覆蓋到。下面這張圖可以清楚的展示出棧的內存佈局:

Grub2: 重定向控制流

如圖中所示,grub_memset()函數的返回地址與用戶名緩衝區之間的距離為16字節。換句話說,如果我們按17次退格鍵,我們就能夠覆蓋到返回地址的最高字節。所以,函數返回地址0x07eb53e8會被替換掉,最終會跳轉到0x00eb53e8。當grub_memset()執行結束時,控制流會重定向到0x00eb53e8,導致系統重啟。同樣的,按退格鍵18,19,20次,都會導致系統重啟。
到這裡,我們能夠重定向控制流了。
我們跳過了對0x00eb53e8,0x000053e8、0x000000e8地址處的代碼分析,因為跳到這幾個地址中,只能導致系統重啟,沒有辦法控制執行流。
雖然成功的構造攻擊跳轉到0×0看起來非常困難,但是我們下面將會展示我們最終是如何做到的。

跳轉到0×0之後系統能否繼續存活?

0×0地址是處理器的IVT(中斷向量表)的入口。這裡包含了大量的段偏移表的指針。

IVT中斷最低地址處的代碼

在啟動的早期階段,處理器和執行框架都還不具備所有的功能。下面是能否成功利用的一些關鍵因素,這在每個系統中可能有所不同:
1.處理器處於“保護模式”,Grub2在最開始的階段會開啟這個模式2.未啟用虛擬內存3.沒有內存保護,內存是可讀/可寫/可執行的,並且沒有NX/DEP保護4.處理器執行32位指令集,即使在64位架構下5.處理器會自動處理動態自修改的代碼:如果寫入影響到一條預取指令,指令隊列將會無效。 6.沒用棧保護機制(SSP)7.沒有開啟地址空間佈局隨機化(ASLR)因此,跳轉到0×0地址並不會造成系統自身崩潰,但是我們需要控制執行流讓代碼走到包含Grub2 Rescue Shell功能的目標函數grub_rescue_run()中。

要跳轉到0×0,需要控制哪些東西?

當用戶按下[Enter]或者[Esc]時,grub_username_get()函數的主循環將會結束。此時,%ebx寄存器中會保存最後一個按鍵的值(Enter的ascii碼為0xd,Esc的ascii碼為0×8)。 %esi寄存器會保存cur_len變量的值。
如上圖所示,指令指針(EIP)指向0×0地址,%esi寄存器的值為-28(利用程序連按了28次退格鍵),然後按下[Enter](%ebx=0xd)。

IVT逆向

如果處理器的狀態像前面所述的那樣(會自動處理動態自修改的代碼),IVT中的代碼就有像memcpy()一樣的功能,會從% esi寄存器指向的地址中拷貝代碼到0×0(IVT自身)。因此,IVT是自修改的代碼,並且我們能夠選擇我們想拷貝的代碼區塊。
下面的步驟展示了代碼真正的執行順序,此時%esi寄存器的值為-28(0xffffffe4):

在第三次循環中,往0×0007處插入了retw指令,此時%esp指向的地址為0xe00c (棧頂返回地址)。
因此,當retw指令執行後,執行流跳到0xe00c。這個地址屬於grub_rescue_run()函數:

通過這步利用,GRUB2進到了grub rescue函數中,我們獲得了一個高權限的shell。

幸運的是,內存雖然被輕微的修改,但是還是能夠使用GRUB的所有功能。 IVT的中斷向量雖然被修改了,但由於處理器現在處於保護模式,IVT不會再被使用。

近一步深入

雖然我們進到了GRUB2 rescue函數中,但卻並沒有真正的通過認證。如果要進入“normal”模式(這個模式提供了grub菜單和完整的編輯功能),GRUB會要求你輸入正確的用戶名密碼。我們可以直接輸入GRUB2命令,甚至引入一個新的模塊來添加一個新的GRUB功能,最終通過往系統裡部署惡意軟件啟動完整的bash shell來獲取一個更便利環境。要運行linux的bash,我們可以使用GRUB2的命令,比如linux, initrd或者insmod。
雖然使用GRUB2命令運行linux內核來部署惡意軟件是完全可行的,但是我們發現了一個更簡單的解決方案,往GRUB2的RAM中寫入代碼補丁來繞過認證,然後再回到“normal”模式。這個方法的思路是修改用戶認證的校驗條件,其相關代碼在grub-core/normal/auth.c 文件中的is_authenticated()函數中。

完成這個修改使用了GRUB2 rescue的命令write_word。這樣,返回GRUB2的“normal”模式的所有條件都已經達成了。句話說,我們不需要用戶名密碼就可以進入GRUB2的“編輯模式”了。

APT攻擊如何使用這個0day?

物理接觸是APT攻擊的一個“高級”特性。 APT攻擊的一個主要目標就是竊取敏感信息。下面是一個非常簡單的例子展示一個APT如何影響系統,持續性的獲取用戶數據的。以下是目標系統配置的概述:
1.BIOS/UEFI 使用密碼進行了保護;
2.GRUB2編輯模式使用了密碼進行保護;
3.擴展啟動方式被禁用:CDROM,DVD,USB,Netboot,PXE…
4.用戶數據被加密。

正如前面提到的,我們的目標是竊取用戶數據。由於數據被加密了,我們的策略是先感染系統然後等待用戶解密數據(通過登錄系統),然後我們直接獲取明文信息。

準備環境部署惡意軟件

通過我們剛剛對GRUB2漏洞利用的分析與展示,我們可以很容易的修改linux入口去加載一個linux內核來獲取root權限的shell。這是一個很老但卻仍然有效的欺騙方法,只需要添加init=/bin/bash到linux入口處,我們就能夠獲取root權限的linux shell,這個環境能夠讓我們更方便的部署惡意軟件。

由於/bin/bash 是第一個啟動的進程,syslog監控還沒有運行,日誌不會記錄。因此,這一入侵將不會被常見的linux監控檢測到。

部署惡意軟件來獲得持續性的控制

為了展示通過利用這個Grub2 0day漏洞能夠做多少事情,我們開發了一個簡單的POC。這個POC可以篡改火狐的鏈接庫,能夠創建一個新線程並啟動一個反彈shell連接到控制服務器的53號端口上。當然這只是一個簡單的例子,在實際場景中的惡意軟件獲取信息會隱秘很多。
將修改後的鏈接庫上傳到virustotal中檢測,55款殺毒引擎沒有一個能檢測出這是一個惡意軟件。火狐是一款web瀏覽器,向HTTP和DNS端口發送請求,所以,我們修改的鏈接庫使用這些端口看起來並不是什麼可疑行為。
為了感染系統我們將被修改的libplc4.so放到USB中然後替換掉源文件。我們必須將USB設備掛載到系統上並且賦予可寫的權限,正如下圖所示:

感染系統

當任意用戶運行火狐時,一個反彈shell就會發起連接。此時,所有的用戶數據都已經被解密了,這允許我們竊取用戶的所有信息。下圖展示了用戶Bob(被攻擊用戶)正在使用火狐瀏覽網頁,而Alice(攻擊者)則完全獲得了Bob的數據。

想要更持續性的控制系統,可以修改一個簡單的內核放到未加密的/boot分區中,來提權部署一個更為持久的惡意軟件,這樣我們就可以為所欲為了。

修復方案

這個漏洞很容易修復,只要防止cur_len溢出就行。目前主流廠商都已經意識到了這個漏洞,因此我們也順便寫了個“緊急補丁”放到GRUB2的git中:

補丁地址:http://hmarco.org/bugs/patches/0001-Fix-CVE-2015-8370-Grub2-user-pass-vulnerability.patch
GRUB 2.02修復命令:

總結
經過我們的深入分析,最終成功利用這個漏洞。但正如文中所說,成功的利用需要很多條件:BIOS版本、GRUB版本、RAM容量、內存佈局能否修改,且每個系統都需要深入的分析去構造特殊的利用。
最後提一下這裡我們沒有利用的地方,大家可以去發散一下:grub_memset()函數可以被濫用以便設置內存的0×00區塊而不跳轉到0×0,另外用戶名和密碼緩衝區也可以被用來存儲payloads。
另外,更複雜的攻擊方法(需要更大的下溢或者payload),可以被用在鍵盤仿真設備上,例如Teensy device。我們可以記錄鍵盤按下的攻擊序列,然後在目標系統上重現。
比較幸運的是,本文所展示的GRUB2漏洞利用方法不是通用的,但卻仍有可能存在其他更多變種的利用在你的環境中生效。

輕鬆做hacker不是夢

提示: 作者被禁止或刪除 內容自動屏蔽

TOP

要係部機前狂按backspace先得喎....用ssh remote唔得禁即係無用啦....除非公司有內鬼...

TOP

故意留的

TOP

你話唔係特登搵鬼信咩

TOP

如果真係得本地用戶先用到呢個exploit, 咁安多兩個門鎖就防到啦

TOP

除左 LOCAL ACCESS,
好多SystemAdmin, 會用 KVMoIP, Dell iDRAC  Console-Redirect-Comport 去做 Remote Maintenance.
由其事 SERVER 放在不同地方 ISP 的 IDC. 放 10 個鎖都冇用.

而且 好多 SystemAdmin, 會特登 做 BackDoor 給自己用.

TOP

你搞得部機,即係可以 boot live CD 啦,個 grub 有無密碼都係無分別

TOP

你搞得部機,即係可以 boot live CD 啦,個 grub 有無密碼都係無分別
leeyc0 發表於 2015-12-20 15:38



    用live cd, 咩都任你睇, 任你加

TOP

提示: 作者被禁止或刪除 內容自動屏蔽

TOP