Fixed Size Migration

2024-06-24

Fixed Size Migration

Author: 堇姬Naup

Why

  • 不能控制輸入長度時,就只能使用原本main function read 來多次輸入 ROP chain
    假設現在空間只夠輸入一個gadget
    1
    payload (2*8 bytes) + rbp + return address(8bytes)
    觀察一下會發現 main_read 其實會將輸入存到 rbp-0x10,可以利用這個特性來寫入 ROP chain
    1
    2
    3
    read
    leave
    ret

leave

1
2
mov rsp rbp
pop rbp

原理

1
2
3
4
空間(8bytes)
空間(8bytes)
old rbp
return address(8bytes)

然後有一塊可以寫ROP的地方buf1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*buf1 - 0x10

*buf1 - 0x08

*buf1

*buf1 + 0x8

*buf1 + 0x10

*buf + 0x18

*buf + 0x20

這裡我們構造

1
2
3
aaaa(padding 0x10)
buf1(old rbp)
main_read

第一次跑的時候,會在底下先遇到一個leave

stack rbp指的地方會從

1
2
3
aaaa(padding 0x10)
buf1(old rbp)<-rbp
main_read

變成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*buf1 - 0x10

*buf1 - 0x08

*buf1 <-rbp

*buf1 + 0x8

*buf1 + 0x10

*buf + 0x18

*buf + 0x20

這時候ret會跳回main read
我們輸入gadget 1 、 gadget 2 、 buf2 、 main read(因為read會把東西存到rbp-0x10)

1
2
3
4
5
6
7
8
9
10
11
12
13
*buf1 - 0x10
gadget 1
*buf1 - 0x08
gadget 2
*buf1 <-rbp
buf2
*buf1 + 0x8
main read
*buf1 + 0x10

*buf1 + 0x18

*buf1 + 0x20

這時候read完會碰到leave,rsp會先指到rbp一樣的位置,然後pop rbp,rsp指到*buf1 + 0x8,而rbp指到*buf2

1
2
3
4
5
6
7
8
9
10
11
12
13
*buf1 - 0x10
gadget 1
*buf1 - 0x08
gadget 2
*buf1
buf2
*buf1 + 0x8 <-rsp
main read
*buf1 + 0x10

*buf1 + 0x18

*buf1 + 0x20
1
2
3
4
5
6
7
8
*buf2 - 0x10

*buf2 - 0x08

*buf2 <- rbp

*buf2 + 0x8

再來ret,會ret到main read

1
2
3
4
5
6
7
8
9
10
11
12
13
*buf1 - 0x10
gadget 1
*buf1 - 0x08
gadget 2
*buf1
buf2
*buf1 + 0x8
main read
*buf1 + 0x10 <-rsp

*buf1 + 0x18

*buf1 + 0x20

寫到rbp-0x10,但我們目標都寫在buf1,所以這輪不寫,直接填充a

1
2
3
4
5
6
7
8
*buf2 - 0x10
aaaaa...
*buf2 - 0x08
aaaaa...
*buf2 <- rbp
buf1 + 0x10
*buf2 + 0x8
main read

main read完leave,rsp指到rbp,rbp拿最上面的拿到buf1 + 0x10,指過去

1
2
3
4
5
6
7
8
9
10
11
12
13
*buf1 - 0x10
gadget 1
*buf1 - 0x08
gadget 2
*buf1
buf2
*buf1 + 0x8
main read
*buf1 + 0x10 <-rbp

*buf1 + 0x18

*buf1 + 0x20
1
2
3
4
5
6
7
8
*buf2 - 0x10
aaaaa...
*buf2 - 0x08
aaaaa...
*buf2 <-rsp
buf1 + 0x10
*buf2 + 0x8
main read

再來ret到main read,寫入資料rbp-0x10(寫入gadget 3、gadget 4、buf2、main read)

1
2
3
4
5
6
7
8
9
10
11
12
13
*buf1 - 0x10
gadget 1
*buf1 - 0x08
gadget 2
*buf1
gadget 3
*buf1 + 0x8
gadget 4
*buf1 + 0x10 <-rbp
buf2
*buf1 + 0x18
main read
*buf1 + 0x20

遇到leave,rsp會先指到rbp一樣的位置,然後pop rbp

1
2
3
4
5
6
7
8
*buf2 - 0x10
aaaaa...
*buf2 - 0x08
aaaaa...
*buf2 <-rbp
buf1 + 0x10
*buf2 + 0x8
main read
1
2
3
4
5
6
7
8
9
10
11
12
13
*buf1 - 0x10
gadget 1
*buf1 - 0x08
gadget 2
*buf1
gadget 3
*buf1 + 0x8
gadget 4
*buf1 + 0x10
buf2,
*buf1 + 0x18 <-rsp
main read
*buf1 + 0x20

之後ret到main ,輸入aaaa(padding 16 bytes),之後 buf1 - 0x18 ,leave

1
2
3
4
5
6
7
8
*buf2 - 0x10
aaaaa...
*buf2 - 0x08
aaaaa...
*buf2 <-rbp
buf1 - 0x10
*buf2 + 0x8
leave

先遇到一次leave,rsp會先指到rbp一樣的位置,然後pop rbp

1
2
3
4
5
6
7
8
*buf2 - 0x10
aaaaa...
*buf2 - 0x08
aaaaa...
*buf2
buf1 - 0x18
*buf2 + 0x8 <-rsp
leave
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
*buf1 - 0x18 <-rbp
隨便
*buf1 - 0x10
gadget 1
*buf1 - 0x08
gadget 2
*buf1
gadget 3
*buf1 + 0x8
gadget 4
*buf1 + 0x10
buf2,
*buf1 + 0x18
main read
*buf1 + 0x20

ret到leave,再做一次leave,rsp會先指到rbp一樣的位置,然後pop rbp,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
隨便<-rbp
...

*buf1 - 0x18
隨便
*buf1 - 0x10 <- rsp
gadget 1
*buf1 - 0x08
gadget 2
*buf1
gadget 3
*buf1 + 0x8
gadget 4
*buf1 + 0x10
buf2,
*buf1 + 0x18
main read
*buf1 + 0x20

之後ret開始執行gadget,這樣就成功寫入gadget並執行了

https://www.youtube.com/watch?v=ogr66Mc-YOk