1. 程式人生 > 其它 >20212818 2021-2022-2 《網路攻防實踐》實踐九報告

20212818 2021-2022-2 《網路攻防實踐》實踐九報告

一、實踐內容

一)軟體安全的概述

1.軟體安全的威脅

  • NIST將安全漏洞定義為:在系統安全流程、設計、實現或內部控制中所存在的缺陷或弱點,能夠被攻擊者所利用並導致安全侵害或對系統安全策略的違反。
  • 隨著計算機技術和網路的發展,軟體的功能越來越強大,已經從嚴格的技術領域擴充套件到社會生活的方方面面。因此軟體安全也已經成為影響經濟與社會生活的重要問題。

2.軟體安全的困境:為什麼軟體中會普遍地存在著安全漏洞呢?

  • 複雜性:計算機軟體經過數十年的發展,現代軟體已變得非常複雜,而且研究趨勢表明,軟體的規模還會更快地膨脹,變得更加複雜。而軟體規模越來越大,越來越複雜就意味著軟體bug會越來越多。
  • 可擴充套件性:現代軟體為了支援更加優化的軟體架構,支援更好的客戶使用感受,往往都會提供一些擴充套件和互動渠道。正是現代可擴充套件軟體本身的特性使得安全保證更加困難
  • 連通性:網際網路的普及使得全球更多的軟體系統都連通在一起,不僅是接入網際網路的計算機數量在快速增加,一些控制關鍵的基礎設施的重要資訊系統也與網際網路建立起了連通性。高度的連通性使得一個小小的軟體缺陷就可能影響非常大的範圍。

3.安全漏洞型別主要存在如下幾類:

  • 記憶體安全違規類:是軟體開發過程中在處理RAM記憶體訪問時所引起的安全缺陷,如緩衝區溢位漏洞。
  • 輸入驗證類:是指軟體程式在對使用者輸入進行資料驗證存時在錯誤,沒有保證輸入資料的正確性、合法性和安全性,從而導致可能被惡意攻擊和利用。
  • 競爭條件類:是系統或程序中一類比較特殊的錯誤,通常在涉及多程序和多執行緒處理的程式中出現。
  • 許可權混淆與提升類:是指計算機程式由於自身程式設計疏忽或被第三方欺騙,從而濫用其許可權,或賦予第三方不該給予的許可權。

(二)緩衝區溢位基本概念

1.緩衝區溢位

  • 緩衝區溢位是計算機程式中存在的一類記憶體安全違規類漏洞,在計算機程式向特定緩衝區內填充資料時,超出緩衝區本身的容量,導致外溢資料覆蓋了相鄰記憶體空間的合法資料,從而改變程式執行流程破壞系統執行完整性。

2.背景知識

  • 編譯器與偵錯程式的使用:Linux環境中要掌握GDB偵錯程式、Windows系統中常用Visual Stdio、VC++等。

  • 組合語言:IA32組合語言中我們要熟悉暫存器和他們的功能,關鍵暫存器及功能如下表:

        

  • 程序記憶體管理:瞭解程序記憶體管理機制是深入理解軟體安全漏洞的必須掌握的內容。

    • Linux系統中的程式在執行時,在記憶體中會為程式建立一個虛擬的記憶體地址空間,用於對映實體記憶體,並儲存程式的指令和資料。
    • Windows作業系統,2GB和4GB為核心態地址空間,用於對映Windows核心程式碼和一些核心態DLL;0GB~2GB為使用者態地址空間,高地址段映射了一些大量應用程序所共同使用的系統DLL,在1GB地址位置用於裝載一些應用程序本身所引用的DLL檔案。
  • 函式呼叫過程:棧溢位攻擊就是針對函式呼叫過程中返回地址在棧中的儲存位置,進行緩衝區溢位,從而改寫返回地址,達到讓處理器指令暫存器跳轉至攻擊者指定位置執行惡意程式碼的目的。

3.緩衝區溢位攻擊原理:根據緩衝區在程序記憶體空間中位置不同,分為棧溢位、堆溢位和核心溢位這三種具體的技術形態。

  • 棧溢位:儲存在棧上的一些緩衝區變數由於存在缺乏邊界保護問題,能夠被溢位並修改棧上的敏感資訊。

  • 堆溢位:儲存在堆上一些緩衝區變數缺乏邊界保護所遭受的溢位攻擊。

  • 核心溢位:存在於一些核心模組或程式中。

  • 溢位攻擊時要考慮的三個問題:需要修改的敏感位置在哪?將敏感位置修改為什麼?執行什麼程式碼以達到攻擊目的?

(三)Linux平臺上棧溢位與Shellcode

1.Linux平臺棧溢位攻擊技術:NSR、RNS、RS三種模式。

  • NSR:主要適用於被溢位的緩衝區變數比較大,足以容納Shellcode的情況,其攻擊資料是從低地址到高地址的構造方式是一堆NOP指令(空操作指令)之後填充Shellcode。
  • RNS:一般被用於溢位的變數比較小,不足以容納Shellcode的情況,攻擊資料是首先填充一些期望覆蓋RET返回地址的跳轉地址,然後是一堆NOP指令填充出著陸區,最後再是Shellcode。
  • RS:這種模式不能精確定位Shellcode在目標漏洞程式中的起始地址,因此無需引入Nop空指令構建“著陸區”。

2.Shellcode實現技術

  • Linux系統中,程式通過“int 0x80”軟中斷來執行系統呼叫,而在Windows系統中通過核心DLL中提供的API介面來完成系統呼叫。

  • Linux本地Shellcode實現:下圖中通過execve()函式啟動/bin/sh提供命令列,但是無法直接將這段c語言程式碼作為注入攻擊負載,我們必須提供以二進位制形式存在的Shellcode。

                        

  • 所對應的組合語言程式碼如下圖所示,分別將execve()函式的引數NULL(0x0)、name變數地址、“/bin/sh”字串地址壓入棧中,然後將eax賦值為execve()系統呼叫號0xb,執行int 0x80軟中斷,完成開啟Shell的功能。
    • 先用高階語言程式設計,Shellcode程式;
    • 編譯並反彙編除錯;
    • 分析程式執行流程;
    • 整理生成的彙編程式碼,儘量減少體積;
    • 提取彙編程式碼所對應的opcode二進位制指令,建立指令組。
    • 遠端Shellcode需要讓目標程式建立socket監聽指定的埠等待客戶端連線,dup()2函式能將標準輸入輸出與socket網路通訊通道進行繫結

(四)Windows平臺上棧溢位與Shellcode

1.棧溢位攻擊技術:與Linux的攻擊技術的差異主要體現在三個方面

  • 對程式執行中廢棄棧的處理方式的差異:程式執行過程中擁有大量的函式呼叫,當一個函式呼叫完返回至呼叫者執行下一條指令前會有恢復棧基和棧頂指標的操作,Windows會向廢棄棧中寫入一些隨機的資料,Linux則不做任何處理。這導致Windows平臺中構建緩衝區資料在棧中植入惡意指令時,會面臨限制。

  • 程序記憶體空間的佈局差異:Linux系統程序記憶體空間中棧底指標在0xc0x0000000之下,這些地址中沒有空位元組;Windows系統棧位置處於0x00FFFFFF以下的使用者記憶體空間一般為0x0012****地址附近,而這些地址的首位元組均為0x00空位元組。

  • 系統功能呼叫的實現方式的差異:Windows通過作業系統中更為複雜的API及核心處理例程呼叫鏈來完成系統功能呼叫。攻擊者在執行shellcode就要考慮系統功能呼叫的區別。

  • Windows系統上典型的Shellcode是啟動一個命令列shell,即“command.com”或“cmd.exe”,API中提供了system()函式呼叫,可以用於啟動指定程式或特定命令。

  • 遠端Shellcode的過程:

    • 建立一個伺服器端socket,並在指定埠上監聽;
    • 通過accept接受網路連線;
    • 建立子程序,執行cmd.exe啟動命令列;
    • 建立兩個管道,命令管道和輸出管道。

(五)堆溢位

Linux在.data、.bss和heap中緩衝區溢位都稱為堆溢位。
1.函式指標改寫:需要被溢位的緩衝區臨近全域性函式指標儲存地址,且在其地址方向。當緩衝區填充資料時,如果沒有邊界判斷和控制的話,緩衝區溢位後就會自然地覆蓋函式指標所在的儲存區。攻擊者只要能將改函式指標指向惡意構造的shellcode地址,在程式使用函式指標是呼叫原先期望的函式時,就會呼叫shellcode。

2.c++類物件虛擬函式表:C++類通過虛擬函式提供了一種Late binding執行過程繫結機制,編譯器為每個包含虛擬函式的類建立起虛擬函式表、存放虛擬函式的地址、虛擬函式指標。對於使用了虛擬函式的機制,如果它的類成員變數中存在可被溢位的緩衝區,那麼就可進行堆溢位攻擊。通過覆蓋類物件的虛擬函式指標指向一個特殊構造的虛擬函式表,進而轉向執行惡意程式碼。

3.Linux下堆管理glibc庫free()函式本身漏洞:Linux作業系統的堆管理是通過glicbc庫實現的,主要目的是增加對多執行緒環境的支援,同時優化記憶體分配和回收的演算法。

(六)緩衝區溢位攻擊防禦技術

    • 嘗試杜絕溢位的防禦技術:解決緩衝區溢位的根本辦法的編寫正確的、不存在緩衝區溢位安全漏洞軟體程式碼,使用一些差錯程式,如falt injection等。
    • 允許溢位但不讓程式改變執行流程的防禦技術:對可能影響到程式流程的關鍵資料結構實施嚴密的安全保護,不讓程式改變其執行流程,從而阻斷溢位攻擊。
    • 無法讓關鍵程式碼執行的防禦技術:嘗試馮.諾依曼體系的本質缺陷,通過堆疊不可執行限制來防禦。

二、實踐過程

 

實踐目標

本次實踐的物件是一個名為pwn1的linux可執行檔案。

該程式正常執行流程是:main呼叫foo函式,foo函式會簡單回顯任何使用者輸入的字串。

該程式同時包含另一個程式碼片段,getShell,會返回一個可用Shell。正常情況下這個程式碼是不會被執行的。我們實踐的目標就是想辦法執行這個程式碼片段。我們將學習兩種方法執行這個程式碼片段,然後學習如何注入執行任何Shellcode。

  • 三個實踐內容如下:

    • 手工修改可執行檔案,改變程式執行流程,直接跳轉到getShell函式。

    • 利用foo函式的Bof漏洞,構造一個攻擊輸入字串,覆蓋返回地址,觸發getShell函式。

    • 注入一個自己製作的shellcode並執行這段shellcode。

任務一:

  手工修改可執行檔案,改變程式執行流程,直接跳轉到getShell函式。

 輸入vi pwn1

 輸入指令%!xxd將顯示改變為十六進位制

 將d7修改為c3。定位到d按下r然後按c,定位到7按下r然後按3

 輸入:%!xxd -r 恢復成十六進位制,然後儲存檔案,執行pwn1。再次執行objdump -d pwn1檢視main函式。可以發現已經修改成功

 執行pwd1發現確實成功了

 任務二:利用foo函式的Bof漏洞,構造一個攻擊輸入字串,覆蓋返回地址,觸發getShell函式。

  反彙編pwn1檔案,命令為 objdump -d pwn1 ,可以看到 pwn1中所有的函式,包括getshell、foo、main。可以知道如果程式正常執行,會執行函式foo。foo函式的功能:將使用者的輸入再次輸出。所以這裡我們可以利用BOF漏洞,通過緩衝區溢位攻擊的方式觸發getshell函式。當foo函式的返回地址是0x080484ba,即foo函式執行完後會呼叫的下一條指令地址為0x080484ba。我們只需將這個地址替換為getshell函式的入口地址,就可以觸發getshell函式。

   首先安裝gdb,後面會用到。

  使用安裝好的gdb除錯分析pwn1 ,命令為gdb pwn1。

  執行這個檔案 ,命令為:r。

   輸入字串,輸入較短字串時,程式可以正常結束執行,但是輸入字串較長時,會出現段錯誤。

        我們讓它顯示具體資訊,命令為info r,可以看到現在EIP的內容是0x33333333。

   生成input檔案,並設定特定的輸入串,命令為:perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"' > input

   通過命令ls檢視當前目錄下的檔案,確定input檔案已成功生成。檢視input檔案的16進位制資訊,命令為:xxd input。

   將input檔案設定為檔案pwn1的輸入,命令為(cat input; cat ) | ./pwn1。

 任務三:注入一個自己製作的shellcode並執行這段shellcode

三、學習中遇到的問題及解決

四、實踐總結