999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

內存地址泄漏分析與防御

2016-08-31 04:38:14傅建明劉秀文李鵬偉
計算機研究與發展 2016年8期

傅建明 劉秀文 湯 毅 李鵬偉

1(空間信息安全與可信計算教育部重點實驗室(武漢大學) 武漢 430072)2(武漢大學計算機學院 武漢 430072)3   (軟件工程國家重點實驗室(武漢大學) 武漢 430072)

?

內存地址泄漏分析與防御

傅建明1,2,3劉秀文1,2湯毅1,2李鵬偉1,2

1(空間信息安全與可信計算教育部重點實驗室(武漢大學)武漢430072)2(武漢大學計算機學院武漢430072)3(軟件工程國家重點實驗室(武漢大學)武漢430072)

(jmfu@whu.edu.cn)

高級持續性威脅(advancedpersistentthreat,APT)攻擊通常會利用內存地址泄漏繞過地址空間布局隨機化(addressspacelayoutrandomization,ASLR)、利用面向返回編程技術(return-orientedprogramming,ROP)繞過數據執行保護(dataexecutionprevention,DEP).針對內存地址泄漏漏洞,以漏洞實例為樣本,剖析了各種造成越界內存訪問的指針或對象的非法操作,以及側信道信息泄漏漏洞,并基于造成內存泄漏的過程,給出了相應的漏洞分類.同時,從漏洞利用和攻擊的過程出發,總結和歸納了內存布局隨機化、內存越界讀寫保護、內存對象內容保護、內存對象地址隨機化等對抗內存地址泄漏的防御方法,從而達到內存布局看不清、內存對象讀不到、內存對象內容讀不懂、關鍵內存地址猜不準的保護目的.最后,提出從程序設計角度提供對內存布局隨機化、代碼地址隨機化、內存對象保護等的支持,同時與操作系統建立協作防御機制,從而構建縱深和立體的安全防御體系.

APT攻擊;內存損壞;內存地址泄漏;地址空間布局隨機化;邊界保護

當訪問的對象不同于期望的對象時,會發生內存損壞,例如對象指針越界、對象未初始化、指針指向的對象不存在等.自20世紀70年代以來,內存損壞一直是軟件的重要漏洞之一,在CERT和CVE漏洞列表中占據前列,如棧溢出、堆溢出、格式化字符串漏洞、NULL指針漏洞、整數溢出、釋放后引用漏洞[1-2]等.內存損壞漏洞一般會導致拒絕服務攻擊、信息泄漏、信息竄改、控制劫持等安全威脅,攻擊者劫持控制流,使得軟件轉向攻擊者設定的代碼(Shellcode).攻擊者植入的Shellcode一般存在于棧或者堆中.為了阻止Shellcode獲得執行權,DEP(W∧X)技術[3]禁止棧和堆中的數據執行.因此,代碼重用技術,如ret2lib[4],ROP[5]、面向跳轉編程技術(jmp-orientedprogramming,JOP)[6]、面向調用編程技術(call-orientedprogramming,COP)[7]等,逐漸被用于Shellcode的編寫,這些技術可以繞過DEP.但這些技術的實施需要獲取重用代碼所在的內存地址.地址空間布局隨機化(addressspacelayoutrandomization,ASLR)可使得代碼在內存中的地址隨著模塊加載而隨機變化,從而降低Shellcode的執行成功率.因此ASLR在Windows,Android,iOS等操作系統中得到了部署.如果攻擊者可以利用地址泄漏漏洞獲得重用代碼的內存地址,則可繞過ASLR.例如,在2014年的APT攻擊事件“雪人行動”中,攻擊者利用CVE-2014-0322漏洞,修改ActionScript腳本中vector對象的長度,從而泄漏內存地址,繞過ASLR防護,最終成功實施了APT攻擊[8].因此,內存地址泄漏成為實施內存損壞攻擊的重要步驟.

APT攻擊可以分為內存地址泄漏、Shellcode注入、控制流劫持、Shellcode的執行和木馬加載等步驟,在該攻擊的每一步驟都可以實施攻擊檢測和防御,如Shellcode的動態檢測[9]、控制流劫持的防御[10-11].文獻[1]總結了內存損壞攻擊的4種普遍類型,并列舉了其對應的防御方法:

1) 代碼損壞攻擊,即利用越界指針(索引)、懸掛指針等內存漏洞達到覆寫程序代碼的目的,其防御方法是代碼完整性(codeintegrity)[12]保護;

2) 控制流劫持攻擊,即通過越界讀寫更改代碼指針,使程序跳轉到攻擊者精心構造的Shellcode或Gadget中執行,其防御方法是代碼指針完整性[10]保護、地址空間隨機化(ASLR)、控制流完整性(codeflowintegrity,CFI)[11]保護;

3) 只面向數據的攻擊,即惡意修改影響程序執行的關鍵數據,如分支變量等,來修改程序邏輯,其防御方法是數據完整性,數據流完整性(dataflowintegrity,DFI)[13];

4) 信息泄漏攻擊,其防御方法數據空間隨機化(dataspacerandomization,DSR)[14]存在2進制代碼級的兼容性問題.文獻[2]按時間順序總結了內存錯誤的發現利用過程,空間內存錯誤的根源在于通過指針解引用實現越界訪問,時間內存錯誤的根源在于通過指針對已被釋放對象再利用.文獻[15]針對CC++編程語言中存在的代碼注入攻擊,闡述代碼補丁、內存管理、動態污點跟蹤、執行路徑監控等保護機制.

本文聚焦在APT攻擊的內存地址泄漏漏洞利用上,從實例出發,分析和總結非法操作引發的地址越界讀寫、側信道攻擊2類地址泄漏漏洞;同時,按照地址泄漏漏洞的攻擊流程,從內存布局推測、內存越界讀寫、讀取對象內容、關鍵地址信息獲取4個階段分析和討論內存地址泄漏的檢測和防御.本文的工作有利于較全面解釋地址泄漏漏洞的本質,為降低內存信息泄漏帶來的危害提供支持,從攻擊源頭阻止或者抑制APT攻擊.

1 內存地址泄漏的基本模型

Shellcode是攻擊者向目標進程注入的攻擊代碼.一般情況下,Shellcode尺寸約幾百字節,其功能包括環境的探測、去DEP、自解密、代碼重定位、獲取系統API地址、下載并運行(或加載)可執行模塊等.另外,Metasploit[16]嵌入了Shellcode的更多功能,如增加用戶、DLL注入、彈框、反向shell等.本文討論的Shellcode由各種重用代碼的地址鏈構成,表1為一個簡單的Shellcode,該Shellcode略去了數據部分,僅由kernel32.dll中代碼對應的地址構成,表示創建一個計算器的進程.如果該Shellcode位于堆中,則需要增加修改ESP的指令(例如movesp,eax).

設Shellcode={a1,a2,…,an},其中ai(1≤i≤n)表示某重用代碼的地址.表1中的Shellcode表示為{0x7c83ed85,0x7c9228cb,0x7c83ed85,0x7c96e68f,0x7c86114d,0x7c80e0bf,0x7c81caa2,0x7c9478e4},這里假設kernel32.dll的基址為0x7c800000.如果kernel32.dll加載時其加載的基址隨機化為0x77b70000,則表1的Shellcode無法執行,因為0x7c83ed85對應的指令不是“Ret”.

Table 1 ROP-based Shellcode表1 基于ROP的Shellcode

內存泄漏攻擊假設在棧或者堆中有一個指針變量vp,例如數據指針或者函數指針,vp指向與Shellcode關聯的模塊中某個固定地址Org_ma.Org_ma表示沒有隨機化的內存地址值.當該模塊的加載地址隨機化后,Org_ma的值變為Aslr_ma.

內存地址泄漏是指攻擊者利用漏洞探測到vp的值Aslr_ma.vp隨模塊隨機化加載前后的基址偏移量Image_offset=Aslr_ma-Org_ma.當前廣泛部署的ASLR機制只會對各可執行模塊的加載基址進行隨機化處理,模塊內部的代碼和數據結構的布局相對固定.攻擊者一旦窺知指針變量vp的值Aslr_ma,根據基址偏移量,可以計算出vp所在模塊內的各指令序列的加載基址.表1中的所有地址加上Image_offset后就可以正常執行.因此,內存地址泄漏攻擊就是泄漏指向模塊空間的指針vp的值,Value(vp)=Aslr_ma.

2 內存地址泄漏漏洞

內存地址泄漏的本質是讀取特定地址的指針數據,然后利用該數據獲得代碼的內存地址.圖1從主動探測——地址越界讀寫、被動偵聽——側信道攻擊2個角度介紹內存地址泄漏攻擊.地址越界讀寫不僅僅是內存空間上的地址越界訪問,更包含邏輯上的越界讀寫,即在程序的正常執行流中,某個內存區域或者寄存器在程序邏輯的角度上是不應該被訪問的或者是攻擊者沒有權限訪問的.側信道攻擊作為一種通過度量開銷信息來間接窺探隱藏信息的攻擊方式,與主流的攻擊方式有很大不同.我們無法把側信道信息與攻擊者完全隔離,攻擊者也無法從開銷信息里推測出完全準確的地址信息.

Fig. 1 Classification of memory address leakage vulnerabilities.圖1 內存地址泄漏漏洞的分類

內存越界讀寫漏洞源于對指針或對象的非法操作.根據非法操作能否使被攻擊對象本身存在可被利用的脆弱點,把針對指針或對象的非法操作分為2類:對象的脆弱屬性和函數的惡意利用.對象的脆弱屬性細分為:對象生命周期管理不規范、對象類型屬性轉換不安全、對象長度屬性修改不合理,這類漏洞的直接后果是改變被攻擊對象的某類脆弱屬性,使攻擊者可以利用該脆弱屬性達到越界訪問的目的;而函數的惡意利用細分為:內存操作函數的惡意利用、格式化函數的惡意利用,這類漏洞作用的被攻擊對象本身不存在不合理的脆弱點,攻擊者通過對這2類函數的惡意利用產生越界復制及內存敏感信息泄漏等后果.

2.1對象的脆弱屬性

對象的脆弱屬性主要包括由釋放后再引用(useafterfree,UAF)漏洞引起的對象生命周期管理不規范,由基本類型混淆、復雜類型混淆漏洞造成的對象類型屬性轉換不安全,由整數溢出漏洞、修改特定數據結構的長度引起的對象長度屬性修改不合理這3類攻擊方式.

2.1.1對象生命周期管理

隨著安全防御技術的發展和部署,傳統的棧溢出和堆溢出漏洞的利用越來越困難.例如,Stack-Guard[17]和StackShield[18]增加了返回地址的保護,HeapGuard[19]增加了Heap完整性的保護,一般的棧溢出或堆溢出都會觸發這些保護機制.UAF漏洞越來越受到攻擊者的追逐,2011,2012,2013年分別有138,177,135個UAF漏洞被曝出[20].

C++對象的創建和銷毀是對偶操作.對象創建后,會對對象中的成員變量賦值,同時,該對象會被其他指針變量引用.當對象銷毀后,對象所占的內存被釋放.但是引用該對象的指針可能沒有被全部清空,或該對象的內容可能沒有被清除,這樣會產生3個問題:

1) 沒有清空的指針稱為懸掛指針[21],因為該指針指向的對象已經被釋放,被釋放的內存會被其他對象占用,則訪問懸掛指針會產生不可預見的后果;

2) 如果該對象釋放的空間被攻擊者控制,則攻擊者可以偽造原對象的函數指針,實現控制流劫持;

3) 如果該對象釋放的空間被攻擊者控制,攻擊者可能會讀取原對象的函數指針,會出現信息泄漏.若該函數指針指向模塊地址,直接導致內存地址泄漏.

基于鏈表的堆塊分配和釋放機制遵循棧式管理,即對于相同大小的堆塊,新分配的堆塊可能是剛剛釋放的相同大小的堆塊.這樣,當使用懸掛指針訪問原堆塊所在的空間時,該空間可能已被其他對象覆蓋重用,甚至是攻擊者精心構造的惡意數據.例如,漏洞CVE-2010-3971中,內存空間的重分配導致引用該舊空間的寄存器被重用.該漏洞在腳本語言中引用CSS文件,對象CSharedStyleSheet偏移0x0d8的位置處有一指針,該指針指向CStyleSheet元素的數組.當mshtml.dll解析到函數CShared-StyleSheet∷Notify()時,會依次取出數組中的元素.當元素內偏移0x18處的值為1時,程序會調用函數CStyleSheet∷Notify().當發現包含CSS文件且CSS文件含有import命令,程序會在數組中創建新元素(CStyleSheet).當元素個數大于當前數組大小時,程序會再分配CSharedStyleSheet數組內存空間.之前數組占用的內存空間被釋放,程序繼續執行并返回到函數CSharedStyleSheet∷Notify()時,存儲數組起始地址的寄存器edi仍然放著以前的內存空間的地址,導致了對數組之前所占用的內存空間的UAF漏洞.

CVE-2014-0322利用特定的函數釋放空間,但該空間仍舊被引用.其中,攻擊者構造一個惡意的網頁,該網頁包含一個“script”元素和“select”元素.當把“select”元素添加到“script”元素上時,函數MSHTML!CElement∷Var_appendChild()被調用,CMarkup對象會被創建,隨后onpropertychange事件被觸發.該事件處理過程中,代碼“this.outerHTML=this.outerHTML”會人為地釋放CMarkup,而CMarkup對象仍被其他變量引用.如果攻擊者構造好數據填充到釋放的空間,則會造成嚴重的后果[22].

在釋放對象沒有被重用的情況下,也可以利用UAF漏洞完成惡意代碼的執行[23].

2.1.2對象類型屬性轉換

攻擊者對被攻擊對象的類型屬性進行非法轉換,達到內存越界訪問的目的,即類型混淆漏洞.根據被攻擊對象的不同,對象類型屬性轉換細分為基本類型混淆漏洞、復雜類型混淆漏洞.基本類型是指編譯器規定的變量類型,而復雜類型則是由基本類型和復雜類型構建的數據結構.

1) 基本類型混淆漏洞

不同類型的指針所指對象類型不同,當不同類型的變量相互轉換時,產生類型混淆漏洞.如果把指向短字節數據類型的指針強制轉換為指向長字節數據類型的指針,則通過對該指針解引用訪問到超過原指向對象邊界范圍的內存,從而產生函數或者數據的指針泄漏[1].例如,把char*轉化為int*的實例時,int類型在內存中占用4B,而char類型在內存中只占用1B,當把指向char類型的指針強制轉換為指向int類型的指針,并對該指針解引用時,編譯器會誤認為其指向對象為int類型,連續讀取4B的內容,從而造成內存越界訪問,產生地址泄漏.

文獻[24]利用指針強制類型轉換獲得一個地址的整數值,可以利用該整數值獲得內存地址的布局.攻擊者首先創建一個object,并創建一個指向該對象的指針thisObject.接著通過強制類型轉換intaddress=*(int*)thisObject;把指針thisObject指向的對象的地址值拷貝到整形變量address中.然后,攻擊者可以通過獲取特定對象的起始地址來推斷可執行模塊的加載基址,因為某些可執行模塊中的特定對象位置相對模塊起始地址是固定的.

2) 復雜類型混淆漏洞

面向對象程序設計語言,如C++和Java語言,可以設計各種復雜的數據結構和數據類型.這些數據類型的相互轉換為數據訪問提供了便利,但不恰當的轉換會帶來安全隱患,例如類型混淆(typeconfusion)[25].

C++提供的4種類型轉換操作符的應用場合和潛在安全問題如表2所示:

Table 2 C++ Type Conversion表2 C++的4種類型轉換

因為static_cast在作下行類型轉換時,沒有動態類型檢查,會引發安全問題.同時,static_cast可以實現把任何類型的表達式轉換成void類型,這種轉換可以繞過編譯器對指針所指對象的類型檢查,便于攻擊者實施攻擊.靜態轉換static_cast應用在C++對象的虛表指針中會造成vtableescape[26]錯誤.

Fig. 2 A case of vtable escape.圖2 vtable escape實例

圖2為vtableescape的實例,其中父類B有2個虛函數,子類D有3個虛函數(其中繼承父類B的2個虛函數).指向父類B的指針被強制轉換(static_cast)為指向子類D,但其所指向的內存地址范圍并沒有變化.當強制引用函數h(·)時,該函數指針并沒有在基類對象的虛函數表中,從而造成內存越界操作.

在2013年的Pwn2Own黑客大賽中,MWRLabs研究人員利用Webkit內核的類型混淆漏洞CVE-2013-2839攻陷了Chrome[25].Webkit的內核C++代碼實現了把HTML的DOM節點轉換為對應標簽對象的結構,再通過這些對象去繪制網頁.把DOM結構(如input,img,able等)轉換為網頁對應標簽對象的類結構時,必須滿足以下條件:1)擁有合理的標簽名稱(如div,table,img等);2)擁有合理的命名空間或者訪問空間.只有同時擁有合理的XMLDOM的local屬性和合理的XMLDOM的namespaceURI屬性,才可以被轉換為HTML的對應標簽對象的類結構.

漏洞CVE-2013-2839是類型轉換漏洞在剪切和書簽服務中的應用.Clipboard是一個剪切和書簽服務,其實現代碼在處理可拖動圖像的過程中,指定拖動圖像被強制轉換為HTMLImageElement對象,該過程中沒有執行適當的檢查,以確保它是一個HTML圖像元素.其漏洞觸發代碼如例1所示:

例1.Typeconfusion1.

if(toElement(node)→hasLocalName

(HTMLNames∷imgTag))

clipboard→setDragImage(static_cast〈

HTMLImageElement*〉(node));

從例1可以看出,在對DOM節點進行標簽類型檢查時,只檢查了其標簽名稱,并沒有檢查其命名空間.這就會產生不合法的HTML圖像元素(比如把SVG元素轉換為HTML的對應圖像的類結構).而HTMLImageElement對象的虛表占用的空間比SVGElement大得多,SVG元素相鄰的存儲器空間被當做HTMLImageElement虛表的一部分被占用.因此,類型混淆漏洞就造成了越界內存的訪問.如果越界的內存區域保存有指向模塊的指針,則該類漏洞會產生內存地址泄漏.

漏洞CVE-2013-0912同樣利用了類型混淆漏洞造成了越界內存訪問.SVG是用XML定義的,用來描述二維矢量及矢量柵格圖形.其中,SVG文檔中的任何元素一般是SVG元素,但其擴展性模塊ForeignObject內可以嵌入非SVG元素.CVE-2013-0912的POC代碼在創建的HTML頁面中引用了SVG文件.而該SVG文件的擴展性模塊中嵌入了一個無效元素,被Webkit解讀為HTMLUnknown-Element,即非SVG元素.通過把該非SVG元素轉換成SVG元素,造成內存越界訪問.其對應的觸發漏洞的Webkit內核代碼語句如例2所示:

例2.Typeconfusion2.

if(!m_contextElement)return0;

returnstatic_cast〈SVGElement*〉

(m_contextElement→treeScope()→

getElementById(m_viewTargetString));

該SVG文件被Webkit視為DOM樹,Webkit根據viewTarget屬性加載SVG文檔的view元素,相當于根據ID屬性選擇DOM樹的節點.從例2代碼可看出,Webkit內核將SVG文檔中ID為m_viewTargetString的元素強制轉換為SVG元素.CVE-2013-0912的POC代碼通過堆噴射進行內存布局,HTMLUnknownElement被安插的位置緊挨著HTMLDivElement元素,當類型混淆漏洞被觸發后,HTMLUnknownElement被視為SVG元素,SVG元素的大小為0x124B,遠遠大于HTMLUnknownElement的0x40B大小.攻擊者可以通過訪問HTMLUnknownElement,越界訪問其相鄰的HTMLDivElement元素的虛表指針.這就通過類型混淆漏洞泄漏了關鍵的內存地址信息.

2.1.3對象長度屬性修改

所有對象和數組都有長度約束,如堆塊塊首包含長度域、數組的索引下標.如果攻擊者修改數據結構的長度約束,則可以讀取給定地址的數據,達到內存地址泄漏的目的.該類漏洞包括整數溢出、修改特定數據結構的長度等.

2014年曝出的心臟出血漏洞(CVE-2014-0160)根源在于OpenSSL密碼庫處理心跳請求包時,對其長度屬性值缺少真實性驗證.TLS心跳包是在客戶端和服務器間定時通知對方自己狀態的一個請求包.TLS心跳請求包中包括有效載荷,payload是有效載荷的期望長度.服務器把有效載荷從請求包復制到響應包,忽略了對請求包大小的邊界檢查,即忽略了payload值的真實性.如果客戶端的有效載荷達不到payload,接收端會把請求包存儲位置之后的任意數據,也當成有效載荷裝進響應包里,返回給發送方,從而造成服務器的敏感信息泄漏.

1) 整數溢出漏洞

整數分為無符號整數(unsignedint)和有符號整數(int).當2個整數相加或者相減時,可能出現上溢或者下溢,得到非期望的數據[1].或者,當把一個有符號的整數轉換為無符號整數時,有可能到一個非期望的大整數[1].整數a(0xfffffff0)和整數b(0x12)相加導致數據上溢,得到一個比期望小很多的整數0x2,而程序仍按照期望的長度(0xfffffff0)訪問數據,導致內存訪問越界.如果越界區域可以覆蓋一個部署好的函數或者數據指針,則發生內存地址泄漏.

CVE-2010-0010是一個整數溢出漏洞:當Apache服務器處理Web用戶提交的分塊數據的長度時,忽略了整數的符號問題,造成因整數溢出引發的堆溢出.Web用戶以分塊編碼的方式向Apache服務器提交數據,數據的長度是一個有符號整數,服務器會為該數據分配一個緩沖區.在把數據拷貝到緩沖區之前,Apache會把用戶提交的分塊編碼的長度與緩沖區長度進行比較,防止拷貝數據越界.攻擊者可以把提交的數據長度設定為負值,繞過該安全檢查.實際上攻擊者提交的數據長度可以大于0x80000000B,造成緩沖區溢出,覆蓋相鄰位置的敏感信息(如數組索引),從而導致信息泄漏.

2) 修改特定數據結構的長度

為便于管理,堆中的數據塊由數據的長度和數據內容2部分構成.如果攻擊者能夠覆蓋數據的長度,則可以實現內存越界訪問,引發信息泄漏.文獻[2]給出了該類攻擊,隨后操作系統加強了對堆的管理,如引入heapcookie、元數據加密等安全機制,增加了攻擊者篡改堆塊數據長度的難度.

腳本語言,如VBScript,JavaScript,ActionScript等,為網頁、文檔、媒體等提供了豐富的交互性、靈活性和可擴展性.VBString就是一種包含長度和數據內容的結構類型,CVE-2012-1876漏洞就是攻擊該數據結構的長度域,越界訪問指向模塊的指針.該漏洞的原理在于可以實現一個任意地址的任意寫漏洞.例3為該漏洞的一個示例:

例3.Arbitraryaddresswrittenvulnerability.

〈tablestyle=“table-layout:fixed”〉

〈colid =“132” width=“41” span=“1”〉

 〈col〉〈table〉

〈script〉

functionover_trigger() {

var obj_col = document.getElementById

(“132”);

obj_col.width=“42765”;

obj_col.span = 1000;

}

setTimeout(“over_trigger();”,15000);

例3首先生成一個id =“132”的CTablelayout對象,利用width和span的值改寫對象的內存,其中width控制改寫的值,span控制改寫的地址及改寫值的寫入次數.隨后執行函數over_trigger(),由于沒有把新引入的span值保存,則寫入內存空間的大小不變,而寫入次數變為1 000,導致寫入空間后緊鄰的內存空間被改寫.攻擊者控制好width和span的值,在寫入空間后面部署VBString,就可以改寫VBString的長度域.如果CButtonLayout對象被部署在VBString之后,因為VBString的訪問空間變大,就可以讀取CButtonLayout對象的虛表指針.由于該指針指向mshtml.dll中的固定偏移量,攻擊者可由該指針值推測mashtml.dll的加載基址.

CVE-2014-0322在產生UAF漏洞后,結合ActionScript3.0的vector屬性,可以實現任意地址的數值加1的操作.vector 是一種經常使用的數據結構,包含一個8B的頭部,其中前4B表示 vector的長度字段size.頭部后為存儲數據的空間,數據元素個數由size決定,每個元素大小為4B.如果V1和V2是連續存放的vector,如(eax+10h)指向V1.size,則執行incdwordptr[eax+10h]后,V1.size為0x03ff.隨后利用ActionScript的腳本直接修改V2.size=V1[0x03fe]=N.N為足夠大的正整數,如0x7fffffff,利用V2[x]就可以訪問V2后的任意地址空間.

Fig. 3 The length field of vector modification in    CVE-2014-0322.圖3 利用CVE-2014-0322修改vector長度

包含長度屬性的數據結構還有ArrayBuffer,Array,Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,DataView等.攻擊者通過修改這些特定數據結構的長度字段實現任意地址的讀寫.

2.2函數的惡意利用

對于不存在敏感屬性被攻擊者利用的被攻擊對象,惡意利用內存操作函數(sprintf,strcpy,strncpy, strncat,memcpy,memset等)會導致越界復制數據;惡意利用格式化函數(fprintf,printf,sprintf,snprintf,vfprintf)則會偷窺棧內敏感信息,最終引發函數或者數據指針的泄漏[27].

2.2.1內存操作函數的惡意利用

文獻[28]給出了一個覆蓋鄰接內存變量,產生信息泄漏或數據改寫的實例.該實例類似于數組賦值中常見的off-by-one漏洞.strncpy(·)只按照給定長度拷貝的字符串,拷貝后不會自動添加NULL.該實例中,客戶端要與服務器端建立起聯系,必須先提交其用戶名和密碼.服務器把客戶端發來的用戶名存儲在數組buff中,用strncpy(·)將其拷貝到user[100]中.如果數組buff中的字符串大于等于100B,user[100]中不存在NULL結束符.但在調用函數snprintf(·)的過程中,程序會從數組user的源地址開始以指定格式復制字符串到數組buff中,直到遇到NULL結束符為止.這樣會泄漏securitycookie、前棧幀ebp、返回地址等堆棧敏感信息.

CVE-2007-3410漏洞就是利用函數strncpy造成棧緩沖區溢出,導致了任意指令的執行.該漏洞存在于RealPlayerHelixPlayer播放器的墻壁時鐘(wallclock),該功能在處理hh:mm:ss:ff時間格式時,忽略了strncpy(buf,pos,len)代碼中buf緩沖區的常數長度.攻擊者對該漏洞造成的棧溢出加以利用,會泄漏棧內的敏感信息.

2.2.2格式化函數的惡意利用(formatstring)

常見的格式化函數有fprintf,printf,sprintf,snprintf,vfprintf,vprintf,vsprintf,vsnprintf等.這些格式化函數可以把變量內容按照指定的格式輸出到給定的緩沖區.如果攻擊者可以控制格式化函數中的輸出格式、輸入的地址、輸出的緩沖區,則會造成嚴重的格式化漏洞.格式化字符串漏洞就是指攻擊者可以控制輸出格式,即在調用格式化的輸出函數時,沒有指定要輸出的字符串的輸出格式.這樣,函數就會在要逐字打印的字符串中尋找特殊的格式字符.

如果要輸出打印的字符包含“%n”,則能寫任意值到攻擊者選定的內存中.因為格式規定符“%n”把前面已經打印的字符長度寫入其對應的實參變量中.該攻擊利用巧妙的布局,可以實現修改程序的返回地址,進而取得程序的控制權.該輸出格式在目前的編譯器中被缺省關閉[29].

如果要輸出的字符串為“%x%x%x%x%x%x%x%x”或“%p%p%p%p%p%p%p%p”[30],但輸出函數并沒有指定其輸出的的格式規定符.攻擊者可以利用這點窺知堆棧中的內容并以16進制的形式輸出.文獻[31]給出了利用格式化字符串漏洞來偷窺程序內容,甚至關鍵函數的返回地址的方法.

2.3側信道攻擊

側信道攻擊利用側信道信息(如時間開銷、空間開銷或者功耗開銷)推測出對攻擊者有用的信息,如加密的密鑰、安全保護措施或者內存地址信息等.

內核空間ASLR能有效阻礙對操作系統內核或驅動程序的本地攻擊.文獻[32]通過針對內存管理系統的通用的側信道攻擊方法,突破了ASLR保護機制的限制,推斷出程序的地址空間布局.文獻[32]中列舉了3種方法:高速緩存探查(cacheprobing)、檢測發生2次頁錯誤的時間差(doublepagefault,DPF)、預加載地址轉換緩存(addresstranslationcachepreloading),這些突破內核ASLR的方法能定位內核空間到頁的粒度.一個用戶模式的應用程序不能直接訪問內核空間,每次在用戶模式下嘗試訪問內核空間內存時會導致一個訪問沖突. 以DPF為例,從用戶模式訪問內存頁p,會導致頁錯誤并傳遞到進程的異常處理.如果p被加載過,即p是已經分配物理內存的頁面,第1次從用戶模式訪問p時,旁路轉換緩沖(translationlookasidebuffer,TLB)會緩存該頁,因此在第2次訪問頁面p時,頁錯誤的傳遞時間會相對較短.如果p沒有被加載過,則不會被TLB緩存,2次頁錯誤的傳遞時間無明顯差別,所以可以根據頁錯誤的傳遞時間估計該頁面是否加載過.DPF方法對內核空間的頁面分配和驅動程序的映射給出一個大致的估計,可以定位到頁面的范圍,但準確定位一個驅動程序的基址還是比較困難的.

模塊級地址隨機化如ASLR、指令級地址隨機化(instructionlocationrandomization,ILR)[33]、基本指令塊(連續的指令序列)地址隨機化(self-trans-forminginstructionrelocation,STIR)[34],在代碼中隨機加入NOP指令模糊Gadget定位如librando[35],這些代碼多樣化技術混淆了執行代碼的內存布局,但文獻[36]提出的故障分析攻擊及計時側信道攻擊在利用內存損壞攻擊越界覆寫后,能識別多樣化代碼中的部分NOP指令,Gadget甚至函數的布局.故障分析攻擊比如攻擊者覆寫數據指針索引,并指向代碼段,如果指針解引用值為0x00,攻擊者則收到報錯信息.借此定位字節0x00,而0x00一般分布在代碼段的常量中,甚至可作為定位Gadget或者函數的明顯特征.同樣改寫數據指針索引,在計時攻擊中,攻擊者通過構造不同輸入,來猜測其指向的棧中關鍵地址值.如下列分支:

1)if(ptr[index] % input==0)

2) i=i×2;

3)else

4) i=i+2.

分支2)明顯比分支4)執行時間長,借此推斷輸入值與修改后的指針解引用值(如返回地址)的關系.但故障分析攻擊及計時攻擊泄漏的信息很大程度上依賴于攻擊者構造值與其收到回應之間映射關系的唯一性,且可利用內存損壞漏洞造成的指針覆寫須直接影響控制流.

3 內存地址泄漏的防御

內存損壞攻擊主要包含4個步驟:

1) 內存布局推測.不管是注入代碼攻擊,還是ROP,JOP,COP等代碼重用攻擊,攻擊者成功攻擊的前提條件是能夠推測出被攻擊對象的內存布局.如果攻擊者無法預知被攻擊對象(如函數指針、虛表指針、函數返回地址、可重用指令序列等)的相關地址信息,則無法達到劫持啊程序控制流,執行惡意代碼的目的.

Fig. 4 Steps and defensive approach of memory corruption attack.圖4 內存損壞攻擊的步驟及防御方法

2) 內存越界讀寫.在攻擊者事先獲知被攻擊對象的內存地址信息的情況下,攻擊者可以控制的進程對象(如與外部輸入相關的數組等)與被攻擊對象在內存布局上還存在一定差距,攻擊者無法直接訪問這些被攻擊對象的信息,只能利用第2節的漏洞達到越界讀寫的目的.

3) 讀取對象內容.如果攻擊者達到越界讀寫甚至訪問整個進程內存空間的目的,防御方則需要對被攻擊對象的內容進行加密.這樣,攻擊者越界訪問到的敏感信息只是加密后的信息,無法獲取真實值.

4) 關鍵地址信息獲取.在攻擊者已經成功獲取泄漏點——被攻擊對象的真實信息(可執行模塊中的函數指針、數據指針、虛表指針)的情況下,執行惡意代碼還需要攻擊者獲取其他關鍵的地址信息,比如可重用代碼的實際地址.

防御方在攻擊者已經成功獲取切入點的情況下,仍然可以通過設置代碼頁不可讀權限阻止大規模的讀代碼行為,或者通過細粒度的地址空間隨機化技術妨礙其窺知攻擊成功所需的其他敏感信息,大大降低內存損壞攻擊的成功率.如果攻擊者突破了以上4層防護,已獲取實施攻擊所需的地址信息,構造攻擊所重用的Gadget,實施代碼重用攻擊.

如圖4所示,針對內存損壞攻擊的4個步驟,主要有如下防御方法:1)對被攻擊對象的相關內存布局進行隨機化處理,增大攻擊者猜測被攻擊對象地址信息的難度;2)對被攻擊對象提供邊界保護,防止攻擊者越界訪問敏感信息;3)對被攻擊對象內容的真實值進行加密,混淆攻擊者獲取的敏感信息;4)設置代碼頁不可讀屬性或部署細粒度的地址空間隨機化技術,降低切入點泄漏帶來的影響.即使面對潛在的代碼重用攻擊,可以從檢測Gadget鏈,控制流完整性2個方面及時檢測甚至阻止攻擊.

本節的防御方法為內存敏感信息(如進程對象的內存基址、指令序列的內存基址等)、虛表指針、數據指針、代碼指針、由指針(索引)訪問的對象、棧內的敏感信息等被攻擊對象提供保護.

3.1內存布局隨機化

攻擊者成功實施攻擊的前提是猜測出被攻擊對象的內存布局,比如函數指針或函數返回地址在棧內存的布局是遵循一定規則排列的,攻擊者可以根據先驗知識,利用與被攻擊對象相鄰的數組或緩沖區,間接修改函數指針或返回地址,成功實施攻擊.如果在棧內存、堆內存、靜態緩沖區中的進程對象分布不可預知,則攻擊者無法獲知被攻擊對象的相關內存布局,也無法成功發起攻擊.本節分別從棧內存、堆內存的內存布局隨機化和結構體內部布局隨機化混淆內存布局.

3.1.1棧內存布局隨機化

攻擊者利用基本棧的緩沖區溢出打破棧內對象邊界,越界讀取敏感信息,甚至篡改控制數據.而傳統的調用棧規則為棧幀及棧內對象的分布提供了可預測性,使棧內對象UAF及未初始化讀取錯誤成為可能.

文獻[37]提出的基于棧的內存錯誤保護——StackArmor——有效混淆了棧內存布局.Stack-Armor提供的隨機棧幀分配器為每個線程調用棧維持多個連續的、由不被映射的PageGuard頁環繞的物理棧幀,并在虛擬地址空間中為邏輯棧幀預定對應的映射項,而映射項對應的物理棧幀序列隨機.這樣,邏輯上相鄰的棧幀其物理分布不可預測.同時,該分配器在設置新棧幀時,會把剛釋放的棧幀映射項與其他任意一個映射項交換,提高了棧幀分配選擇的隨機性.StackArmor通過2進制級插樁調用該分配器為靜態分析時篩選出的棧幀及緩沖區提供保護.涉及到局部變量指針計算的函數棧幀,是潛在的被攻擊對象,程序在該函數調用點為其隨機分配并切換到新棧幀,并在調用結束后返回到原始堆棧繼續執行.作為攻擊者的可控棧內對象,如果某個緩沖區的所有引用不用作訪問其他內存對象,則可將其獨立放置到隨機分配的新棧幀中.被隔離的函數棧幀和緩沖區使越界讀寫完全失效.StackArmor結合了靜態分析和插樁的策略,在利用新棧幀隔離可控對象及被攻擊對象的基礎上,隨機化處理新棧幀的分配布局,攻擊者無法通過棧內可控對象推測被攻擊對象的布局.

3.1.2堆內存布局隨機化

基于鏈表的堆塊分配和釋放機制是遵循棧式管理的,攻擊者可以利用該特性明確內存布局,這為通過越界內存訪問獲取敏感地址信息提供了很大便利.

在CVE-2012-1876漏洞利用中,攻擊者首先通過腳本申請16個Button對象,每個Button對象大小為0x100,同時設置每個Button對象的ClassName,Title(長度均為0x100的字符串對象).接著釋放掉16個ClassName占用的0x100大小的空間,這樣將會在剛申請的內存空間上留下16個“小孔”.然后,攻擊者申請0x100大小的Spanstructure,希望Spanstructure落在16個小孔中的一個.繼續釋放Button對象的Title,同時大量申請長度為0x100的VBString,將剛釋放掉的堆空間填充.最后,利用該漏洞修改VBString的長度,實現對給定地址的讀操作,達到內存信息(地址)泄漏的目的.

在遵循棧式管理的內存分配機制下,攻擊者利用UAF及2次釋放漏洞精確控制被攻擊對象相鄰的內存布局.針對UAF漏洞根源——懸掛指針解引用,Undangle[38]和FreeSentry[39]在程序運行時插入動態檢查,起到一定程度的防御作用.Undangle[38]利用動態污點分析工具跟蹤程序在指定輸入下的執行軌跡,其核心EarlyDetection技術從執行軌跡中識別懸掛指針的創建點,跟蹤懸掛指針在執行流中的傳播,直到再次使用該懸掛指針,從而及時檢測出UAF及2次釋放漏洞.FreeSentry對指針創建及指針指向對象修改操作插入自定義的函數regptr(),記錄指針地址,引用對象的邊界等信息,當捕獲到釋放內存函數時,將引用對應內存塊的所有懸掛指針指向無效內存地址.FreeSentry可擴展為邊界檢查.而DANGNULL[40]則在LLVM的中間代碼級進行靜態插樁,識別指針分配操作并插入軌跡函數,在運行時建立指針和內存對象之間的引用關系,并追蹤堆內存分配、釋放函數,及時發現懸掛指針并使其失效,從根本上阻止懸掛指針解引用,但廢棄不被解引用的良性懸掛指針會帶來額外開銷.

如果增加相同大小的堆塊在內存分布的隨機性,突破棧式管理中內存分配釋放的特性,那么攻擊者部署2個鄰接對象,精確對象的內存布局的難度就會大大增加.文獻[41]中提出了一種基于虛擬簇的堆塊分配機制.每次分配大小為A的對象時,從虛擬簇中大小為A的堆塊和2倍大小為A的堆塊中分配一塊.因此,該機制擴大堆塊待分配的空間和打亂分配順序,以此提高堆塊分配的隨機性,降低釋放后被分配的概率.這樣,攻擊者越界訪問的對象并不可控.DieHard[42]是隨機化的內存管理器,應用程序對應的堆空間大小是其所需最大空間的M倍(M≥2).程序所請求堆塊對應的堆區域(相同大小的堆塊區域)只允許至多填滿1M的空間,且剛剛釋放的堆塊與同堆區域內的空閑堆塊有相同概率被下次分配操作選中.DieHarder[43]的分散頁布局參考了OpenBSD的內存分配機制,利用系統調用mmap()實現進程對象到內存之間的分散頁映射,即內存頁面不連續.分散頁之間的空隙是未被映射的內存,該內存作為PageGuard預防內存的越界訪問.

上述內存分配的隨機化增加了內存布局的不確定性.當然,該隨機化需要修改內存的分配機制,增加了空閑的內存空間,同時也增加了內存分配的開銷.

3.1.3結構體內部布局隨機化

結構體是攻擊者劫持程序執行流的主要利用目標.在緩沖區溢出漏洞中,攻擊者通過越界覆寫棧中與用戶輸入相關的數組,修改函數的返回地址.在包含有函數指針的結構體中,攻擊者控制與函數指針相鄰的外部輸入變量,篡改函數指針.

文獻[44]中提出的基于封裝結構的隨機化方法在一定程度上緩解了上述攻擊過程.這種隨機化方法利用了編譯器GCC,在源程序中的函數、結構體以及類這些數據結構的抽象語法樹(AST)生成以后,隨機更改其內部數據成員的鏈表串接順序.隨機化策略是:1)在靠近被攻擊對象(函數返回地址及函數指針)的相對低地址處布置“哨兵”(Guard區域);2)在與用戶輸入相關的數組之間布置“哨兵”;3)分別隨機化處理與用戶輸入相關的數組、與輸入無關的數組、其他變量(包括函數指針)這3類數據結構的內存排列.這樣,通過在運行時檢查Guard區域是否被覆寫,及時檢測出緩沖區溢出.同時,這種結構體內部隨機化增加了猜測被攻擊對象內存布局的難度.

自動結構體隨機化[45]對占有相同大小內存空間的域實現內存布局隨機化.這里的域包括CC++程序中出現的各種數據類型,最常用的是int,char,long等基本類型及結構體.文獻[45]的自動隨機化算法掃描包含數據變量的結構體,構建鄰接表,其縱向鏈節點保存不同類型(占內存空間不同)的域,橫向鏈節點保存相同類型(占內存空間相同)的域,遍歷每個橫向鏈表,對其域節點的串接順序進行隨機化處理.

這2種細粒度的隨機化方法部署在函數內部、結構體、類內部,使攻擊者無法預知結構體域排列的特點,降低攻擊者越界篡改被攻擊對象的成功率.

本節內存布局隨機化方法的對比分析如表3所示:

Table 3 Method Comparison about Memory Layout Randomization表3 內存布局隨機化的方法比較

3.2內存越界讀寫保護

攻擊者得到被攻擊對象的內存布局后,會試圖獲取被攻擊對象的內容.例如,棧內存信息有其固定分布特征,攻擊者可以預知函數返回地址和可控變量的內存排列,但卻無法直接打印出函數返回地址值,只能利用格式化字符串攻擊等獲得字符串后面的敏感信息.這里的越界讀寫不僅指內存空間的越界,也包括邏輯上的越界訪問,如已釋放的空間里的信息不應該被訪問,但越界獲取釋放對象的遺留信息造成UAF漏洞.內存越界讀寫需要可控對象作為跳板,獲得被攻擊對象的訪問權限.這里分別從界定可控對象訪問范圍、設置被攻擊對象不可讀取權限2個方面分析內存越界讀寫的防御方法.我們選取了虛表指針、數據指針、由指針(索引)訪問的對象、棧內的敏感信息4類典型的攻擊者可控對象,討論其合理的訪問范圍,并分析當針對4類可控對象的越界保護失效后,如何設置被攻擊對象(代碼指針、虛表指針等指向關鍵代碼的地址信息)的訪問權限,才能使越界訪問無效.

3.2.1界定可控對象的合理訪問范圍

1) 虛表指針保護

UAF漏洞和類型混淆漏洞會涉及到虛表指針,對虛表指針的保護可以抑制攻擊者進行內存越界讀寫,從而阻止內存地址的泄漏.

對于UAF漏洞,對象A被釋放后,其占用的地址空間被其他對象填充.因為C++對象的前4B是虛表指針,攻擊者把占用對象的前4B填充為精心構造的地址信息Addr(如與被攻擊對象關聯的固定指針變量vp的地址).攻擊者對懸掛指針解引用并調用對象A中的虛函數時,程序轉向越界訪問Addr處的內容,造成關鍵地址信息泄漏.如果Addr處的變量是數據指針,則發生了指針類型沖突(把虛表指針視為代碼指針).為此,PointerScope[46]為X86指令系統設計了指令操作數類型限制規則,如MOV等數據傳輸指令的2個操作數的類型相同,MUL,DIV指令的操作數類型是整數,JMP,JZ等控制流相關指令的操作數是控制指針,這種類型界定和類型傳播為類型推理算法提供了依據,把指針誤用檢測轉化為類型沖突檢測.

對于類型混淆漏洞,攻擊者可通過解引用虛表指針,引起父類和子類虛函數的混淆調用,最終造成內存越界訪問,如圖2中的vtableescape錯誤.這類由虛表指針引起的內存越界訪問,直接后果是錯誤的虛函數調用.對虛函數調用的檢查,也能及時檢測虛表指針是否發生錯誤解引用.SAFEDISPATCH[47]提供2種級別的C++虛函數調用檢查:針對對象實例的方法實現、針對對象的虛表.虛函數的作用是因對象繼承而采用不同的策略實現函數名相同的不同方法.在編譯時分析調用虛函數的對象,確定其指針或引用的靜態類型,靜態類型必須聲明為該對象的基類指針或者引用.在運行時,C++的動態調度機制確定調用虛函數的對象實際類型,是本身基類類型還是其子類類型.虛函數的調用保護包括靜態類層次分析(classhierarchyanalysis,CHA)和運行時檢查2個階段.CHA分析需要編譯器對源代碼進行靜態分析,確定虛函數合理的調用點范圍(基類和子類的虛函數),并以ValidM表格的形式表示.在運行時,把獲得的虛函數指針與ValidM中規定的方法實現對比,把虛函數的調用點控制在ValidM規定的合理范圍內.

2) 數據指針保護

指針是C或C++重要的數據結構,為程序的靈活性和可擴展性提供了支持,攻擊者往往劫持函數返回地址、虛函數地址、或者其他指針,達到控制劫持或者數據劫持的目的.基本類型混淆漏洞以及修改指針索引造成的越界訪問,都離不開對指針的非法操作.

SoftBound[48]通過對CC++語言中的數據指針進行邊界檢查來保證內存訪問的安全性,可以保護內存、寄存器、函數返回值中的指針.針對存儲在寄存器的指針值,生成對應的基址base標識和指針范圍bound標識.對于每一次指針的內存訪問,SoftBound在其前面插入check函數,來保證無指針越界訪問.針對存儲在內存的指針,SoftBound會利用查找表,在指針地址與元數據表(包括指針對應的base標識和bound標識)之間建立映射,在取指針值時,SoftBound會插入查表指令,來獲取該指針對應的base和bound值;在存入指針值時,SoftBound更新查找表里的相應指針項.

類型化內存模型[49]把C語言環境中的字節內存模型抽象為由字節域和類型域組成的內存塊,其中字節域即常規的有序數據內容,類型域則是其對應的類型集合.這種內存安全模型的核心準則是,保證按照數據類型的寫入類型mt的兼容類型mt′進行讀取,而所占字節數量相等的2種數據類型則視為兼容類型.基于該安全準則,在內存讀寫操作中,該模型會先根據讀寫內容的數據類型判斷目的內存地址范圍是否合法.

3) 對象邊界保護

內存操作函數的惡意利用破壞了原有的對象邊界,整數溢出漏洞惡意修改了訪問對象的索引,本節討論這些攻擊的檢測與防御.

SoftBound從指針保護的角度阻止了內存的越界訪問.同理,保護用指針訪問的對象也可以阻止內存的越界訪問.WIT(writeintegritytesting)[50]對中間語言代碼進行靜態的指針分析和寫安全性分析.指針分析就是尋找每個指針的指向對象的集合(包括局部變量、全局變量及動態分配的內存對象),即PTS(points-toset).每個指針及其對應的PTS安全級別相同(以顏色標記安全級別).寫安全性分析就是確定每條指令的安全級別.寫指令與其目標內存地址顏色一致,間接調用指令與其對應的目標函數顏色一致.但是,WIT并不能阻止越界讀操作,因為讀指令被默認為安全級別.而越界讀操作會引發內存關鍵信息的泄漏,如內存地址泄漏.

WIT把對象邊界與其對應的語義(同一指針指向的PTS,寫指令的目標內存地址,間接調用指令的目標函數)聯系起來.BaggyBoundsChecking[51]根據對象類型不同,在程序執行的不同階段記錄對象邊界信息.在每次為對象分配內存時,BaggyBoundsChecking會多分配若干字節,使分配內存大小滿足2n.它利用內存對象邊界表[52]記錄對象邊界信息,根據malloc(·),free(·)等函數更新堆塊的邊界信息,在調用函數和函數返回時更新棧內局部變量的邊界信息,在程序啟動時更新全局變量的邊界信息.

對內存操作函數的惡意利用會破壞原有的對象邊界.基于規則的代碼補丁[53]對CC++中可能造成緩沖區溢出的代碼段進行修改并重新編譯,在不改變程序邏輯基礎上,很大程度上阻止內存函數越界復制等漏洞.其中補丁規則比如用函數strncpy替代函數strcpy,對索引值進行取模運算限制訪問范圍,對指針運算結果添加必要檢查,對內存輸入函數添加長度參數等等.在目標緩沖區的末尾添加“

主站蜘蛛池模板: lhav亚洲精品| 国产特级毛片aaaaaa| 亚洲精品欧美日本中文字幕| 蜜桃臀无码内射一区二区三区 | 亚洲狠狠婷婷综合久久久久| 欧美成人免费午夜全| 日本黄网在线观看| 天天综合色网| 国产电话自拍伊人| 成年人视频一区二区| 免费国产在线精品一区| 在线免费看黄的网站| 婷婷激情亚洲| 毛片卡一卡二| av大片在线无码免费| 2022精品国偷自产免费观看| 国产精品网曝门免费视频| 国产成人精品亚洲日本对白优播| 97超爽成人免费视频在线播放| 亚洲一区第一页| 国产白浆在线观看| 青青操国产视频| 久久久久国产一级毛片高清板| 久久国产av麻豆| 亚洲毛片在线看| 99视频精品在线观看| 国产日韩AV高潮在线| 国产欧美精品一区二区| 国产日本一线在线观看免费| 中文字幕在线播放不卡| 亚洲欧美综合在线观看| 久久精品人妻中文视频| 人人91人人澡人人妻人人爽| 五月天在线网站| 日韩福利在线视频| 亚洲精品福利网站| 国产视频只有无码精品| 国产精品所毛片视频| 狼友视频一区二区三区| 人妻无码中文字幕一区二区三区| 色成人综合| 麻豆a级片| 18禁色诱爆乳网站| 欧美精品1区2区| 亚洲精品国产综合99| 国产成人一级| 国产精品亚洲精品爽爽| 国产女人爽到高潮的免费视频| 自拍偷拍欧美日韩| 国产日韩精品一区在线不卡| 青青操国产视频| 日韩精品一区二区三区swag| 92午夜福利影院一区二区三区| 99久久精品免费观看国产| 成年A级毛片| 亚洲六月丁香六月婷婷蜜芽| 福利一区三区| 国产成人精品免费视频大全五级| 亚洲精品国产日韩无码AV永久免费网 | 亚洲国产天堂久久九九九| 91精品最新国内在线播放| 亚洲精品777| 午夜视频在线观看免费网站| 欧美影院久久| 最新国产精品第1页| 尤物成AV人片在线观看| 色悠久久久| 日本久久网站| 999精品视频在线| 四虎成人精品| 久久人搡人人玩人妻精品一| a级毛片毛片免费观看久潮| 国产三级韩国三级理| 19国产精品麻豆免费观看| 亚洲av无码牛牛影视在线二区| 男女性午夜福利网站| 五月天综合婷婷| 国产极品美女在线观看| 青青青视频免费一区二区| 国产剧情国内精品原创| 人人爱天天做夜夜爽| 露脸国产精品自产在线播|