linux kernal pwn WCTF 2018 klist(一)

本文探讨了一种利用UAF漏洞的方法,通过控制管道中的数据结构来间接实现任意地址写,介绍了条件竞争导致的uaf问题,并提及了传统攻击手段的限制。重点在于学习者如何巧妙地运用管道机制绕过权限限制,实现攻击目标。
摘要由CSDN通过智能技术生成

启动脚本

#!/bin/sh

qemu-system-x86_64 -enable-kvm -cpu kvm64,+smep -kernel ./bzImage -append "console=ttyS0 root=/dev/ram rw oops=panic panic=1 quiet kaslr" -initrd ./rootfs.cpio -nographic -m 2G -smp cores=2,threads=2,sockets=1 -monitor /dev/null -nographic

开了smep 开了kaslr
看到可以所线程
那就考虑条件竞争了

init脚本

#!/bin/sh

mount -nvt tmpfs none /dev
mknod -m 622 /dev/console c 5 1
mknod -m 666 /dev/null c 1 3
mknod -m 666 /dev/zero c 1 5
mknod -m 666 /dev/ptmx c 5 2
mknod -m 666 /dev/tty c 5 0
mknod -m 0660 /dev/ttyS0 c 4 64
mknod -m 444 /dev/random c 1 8
mknod -m 444 /dev/urandom c 1 9
chown root:tty /dev/console
chown root:tty /dev/ptmx
chown root:tty /dev/tty
mkdir -p /dev/pts
mount -vt devpts -o gid=4,mode=620 none /dev/pts

mount -t proc proc /proc
mount -t sysfs sysfs /sys

cat /root/signature

echo 0 > /proc/sys/kernel/kptr_restrict
echo 0 > /proc/sys/kernel/dmesg_restrict

insmod /list.ko
mknod /dev/klist c 137 1
chmod a+rw /dev/klist
cat /proc/kallsyms |grep commit_cred
lsmod
#cat /sys/module/list/sections/.text 
setsid cttyhack setuidgid 1000 sh

umount /proc
umount /sys

halt -d 1 -n -f

init脚本看得到
驱动是list.ko
而且改了/dev/ptmx权限,那么我们就无法劫持tty结构体,无法覆盖ptmx。

分析一下整个程序

在这里插入图片描述

在这里插入图片描述
ioctl看得出来四个功能
0x1337
0x1338
0x1339
0x133A

0x1337是add
在这里插入图片描述
参数是一个地址,这地址放着两个值
第一个是size 第二个是指针。

然后kmalloc申请一个(size + 24)大小的object
object里面的结构长这样

00000000 item            struc ; (sizeof=0x20, mappedto_5)
00000000 refcount        dd ?
00000004 field_4         dd ?
00000008 size            dq ?
00000010 next            dq ?                    ; offset
00000018 data            dq ?
00000020 item            ends

第一个值记录这个item被引用过多少次
然后直接设为1

size是传入的size
data是从传进来的那个指针那里拷贝进来的数据。

如果一个字节没拷贝进来就说明size是0
就没用 free掉object就行

拷贝成功就放到glist中
然后next指针是记录之前glist直接管理那个object

就是形成了一个链表。

select_item
在这里插入图片描述传入一个参数idx
然后在glist的链表中寻找

如果idx太大等问题就退出

找到之后调用了一下这里的get
在这里插入图片描述
这是加一的原子操作

就是把object中的记录item被引用多少次那个指针加一。

puts
在这里插入图片描述
原子减一操作
如果减完是0就free掉

他整个的逻辑就是找一个放在(fd+200)
对所选的gets
之前所选的也就是(fd+200)的puts

remove_item
在这里插入图片描述逻辑简单
就通过idx在链表中找到
拿走
然后电泳puts
原子减一
如果为0free掉。

list_head
在这里插入图片描述把链表头拿出来,里面的数据拷贝给用户。

list_open
在这里插入图片描述
申请了一个object放在了fd_200

list_read
在这里插入图片描述从fd+200那个object那里来读最多size个字节

list_write
在这里插入图片描述往进写最多size字节

list_release
在这里插入图片描述
原子操作减一

漏洞在list_head
list_head原本的逻辑是先get 然后链表头取出来把数据拷贝出来,然后puts
但是上的锁在get之后puts之前就解锁了
如果这里有另一个进程进来通过add_item来改变了glist
add之后count是1 新的item puts之后减一会直接free
那么这里就造成了一个uaf

所以就是double fetch 造成的一个uaf。

利用方法
1、uaf我们之前遇到过一个 2017 babydriver
我们直接通过uaf分配到一个cred 然后改权限

但是问题来了
我们的write只能write从24个字节开始
刚好把提权那部分避过去了

2、我们又想到可以打开/dev/ptmx结构体覆盖ptmx结构体或者tty结构体
但是init脚本中对ptmx文件更改了权限
普通用户打不开了 也行不通

我们之前学习的几种利用方式
因为ptmx相关的几种不能用了
剩下几种也都是需要任意地址写来完成

那依然如此我们的思路就转化成我们现在已有的这个uaf如何能转化成任意地址写?

这里学习大佬思路学到了能用管道。
在创建pipe管道的时候会申请一个这样的结构

struct pipe_buffer {  
    struct page *page;  
    unsigned int offset, len;  
    const struct pipe_buf_operations *ops;  
    unsigned int flags;  
    unsigned long private;  
};  

其中page是pipe存放数据的缓冲区
offset和len是数据的偏移和长度
offset len可以根据我们在管道中传输的内容来变化

那么如果我们一开始申请一个跟这个结构一样大的堆
然后条件竞争释放掉
申请管道申请到
我们就可以通过控制管道来控制结构体里面的内容
我们控制offset len的时候刚好可以控制结构体的size位

直接改的很大
就又是任意读写。

网上找了找exp
感觉还挺多
都拿过来学习学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值