首页
社区
课程
招聘
[原创]Linux Kernel Pwn_3_ret2usr
发表于: 2020-10-4 01:30 6136

[原创]Linux Kernel Pwn_3_ret2usr

2020-10-4 01:30
6136

原理:攻击利用了 用户空间的进程不能访问内核空间,但内核空间能访问用户空间 这个特性来定向内核代码或数据流指向用户控件,以 ring 0 特权执行用户空间代码完成提权等操作。

图片描述

可以看到比较重要的就是:

注意,此时开启了Kaslr保护。但是没有smep保护

这里遇到了一个插曲,当我尝试启动内核的时候,提示:
图片描述
属实令我感到非常奇怪。然后我尝试将qemu启动脚本 中的 -m 64M改成:-m 256M。
成功启动!

保护如下:
图片描述

通过ioctl来切换到不同的函数执行

如果我们可以控制拷贝的长度到canary,那么就可以把内核中的canary泄漏到用户态

(1) 通过kallsmys获取 commit_creds(),prepare_kernel_cred() 的地址。同时拿到加载的时的地址偏移。(以及gadgets)
(2) 通过ioctl设置off,通过copy_to_user把canary拉到用户态,达到泄漏canary的目的。
(3) 通过core_write向内核态全局变量name上写rop链。
(4) 通过core_copy_func把name上的内容写到内核栈上,bypass canary,覆盖返回地址。
(5) 通过执行ROP链来进行:调用commit_creds(prepare_kernel_cred(0))完成提权。
(6) 重新返回用户态,“着陆”起shell。

https://www.anquanke.com/post/id/172216#h2-9
https://blog.csdn.net/qq_41071646/article/details/95768194
https://www.jianshu.com/p/8d950a9d8974

mv core.cpio core.cpio.gz
gzip -d ./core.cpio.gz
cpio -idmv < core.cpio
mv core.cpio core.cpio.gz
gzip -d ./core.cpio.gz
cpio -idmv < core.cpio
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
/sbin/mdev -s
mkdir -p /dev/pts
mount -vt devpts -o gid=4,mode=620 none /dev/pts
chmod 666 /dev/ptmx
cat /proc/kallsyms > /tmp/kallsyms
echo 1 > /proc/sys/kernel/kptr_restrict
echo 1 > /proc/sys/kernel/dmesg_restrict
ifconfig eth0 up
udhcpc -i eth0
ifconfig eth0 10.0.2.15 netmask 255.255.255.0
route add default gw 10.0.2.2
insmod /core.ko
 
poweroff -d 120 -f &
setsid /bin/cttyhack setuidgid 1000 /bin/sh
echo 'sh end!\n'
umount /proc
umount /sys
 
poweroff -d 0  -f
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
/sbin/mdev -s
mkdir -p /dev/pts
mount -vt devpts -o gid=4,mode=620 none /dev/pts
chmod 666 /dev/ptmx
cat /proc/kallsyms > /tmp/kallsyms
echo 1 > /proc/sys/kernel/kptr_restrict
echo 1 > /proc/sys/kernel/dmesg_restrict
ifconfig eth0 up
udhcpc -i eth0
ifconfig eth0 10.0.2.15 netmask 255.255.255.0
route add default gw 10.0.2.2
insmod /core.ko
 
poweroff -d 120 -f &
setsid /bin/cttyhack setuidgid 1000 /bin/sh
echo 'sh end!\n'
umount /proc
umount /sys
 
poweroff -d 0  -f
qemu-system-x86_64 \
-m 64M \
-kernel ./bzImage \
-initrd  ./core.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr" \
-s  \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic  \
-gdb tcp::1234
qemu-system-x86_64 \
-m 64M \
-kernel ./bzImage \
-initrd  ./core.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr" \
-s  \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic  \
-gdb tcp::1234
 
__int64 init_module()
{
  core_proc = proc_create("core", 0x1B6LL, 0LL, &core_fops);    //创建一个proc虚拟文件,应用层通过读写该文件,即可实现与内核的交互。
  printk(&unk_2DE);        //输出提示符:6core:created /proc/core entry
  return 0LL;
}
__int64 init_module()
{
  core_proc = proc_create("core", 0x1B6LL, 0LL, &core_fops);    //创建一个proc虚拟文件,应用层通过读写该文件,即可实现与内核的交互。
  printk(&unk_2DE);        //输出提示符:6core:created /proc/core entry
  return 0LL;
}
__int64 __fastcall core_ioctl(__int64 a1, int choice, __int64 a3)
{
  __int64 v3; // rbx
 
  v3 = a3;
  switch ( choice )
  {
    case 0x6677889B:
      core_read(a3);        //从内核态拷贝栈上数据到用户态
      break;
    case 0x6677889C:
      printk(&unk_2CD);
      off = v3;            //根据ioctl传进来的参数设置off
      break;
    case 0x6677889A:
      printk(&unk_2B3);
      core_copy_func(v3);
      break;
  }
  return 0LL;
}
__int64 __fastcall core_ioctl(__int64 a1, int choice, __int64 a3)
{
  __int64 v3; // rbx
 
  v3 = a3;
  switch ( choice )
  {
    case 0x6677889B:
      core_read(a3);        //从内核态拷贝栈上数据到用户态
      break;
    case 0x6677889C:
      printk(&unk_2CD);
      off = v3;            //根据ioctl传进来的参数设置off
      break;
    case 0x6677889A:
      printk(&unk_2B3);
      core_copy_func(v3);
      break;
  }
  return 0LL;
}
unsigned __int64 __fastcall core_read(__int64 new_off)
{
  __int64 v1; // rbx
  __int64 *v2; // rdi
  signed __int64 i; // rcx
  unsigned __int64 result; // rax
  __int64 v5; // [rsp+0h] [rbp-50h]
  unsigned __int64 v6; // [rsp+40h] [rbp-10h]
 
  v1 = new_off;
  v6 = __readgsqword(0x28u);
  printk(&unk_25B);
  printk(&unk_275);
  v2 = &v5;
  for ( i = 16LL; i; --i )
  {
    *(_DWORD *)v2 = 0;
    v2 = (__int64 *)((char *)v2 + 4);
  }
  strcpy((char *)&v5, "Welcome to the QWB CTF challenge.\n");
 
  result = copy_to_user(v1, (char *)&v5 + off, 0x40LL);    //向用户态拷贝0x40个字节的内容,内核空间的拷贝起始地址可控(通过off)
 
  if ( !result )
    return __readgsqword(0x28u) ^ v6;
  __asm { swapgs }
  return result;
}
/*
内核空间-->用户空间
copy_to_user函数
unsigned long copy_to_user(void *to, const void *from, unsigned long n)
to:目标地址(用户空间)
from:源地址(内核空间)
n:将要拷贝数据的字节数
返回:成功返回0,失败返回没有拷贝成功的数据字节数
*/
unsigned __int64 __fastcall core_read(__int64 new_off)
{
  __int64 v1; // rbx
  __int64 *v2; // rdi
  signed __int64 i; // rcx
  unsigned __int64 result; // rax
  __int64 v5; // [rsp+0h] [rbp-50h]
  unsigned __int64 v6; // [rsp+40h] [rbp-10h]
 
  v1 = new_off;
  v6 = __readgsqword(0x28u);
  printk(&unk_25B);
  printk(&unk_275);
  v2 = &v5;
  for ( i = 16LL; i; --i )
  {
    *(_DWORD *)v2 = 0;
    v2 = (__int64 *)((char *)v2 + 4);
  }
  strcpy((char *)&v5, "Welcome to the QWB CTF challenge.\n");
 
  result = copy_to_user(v1, (char *)&v5 + off, 0x40LL);    //向用户态拷贝0x40个字节的内容,内核空间的拷贝起始地址可控(通过off)
 
  if ( !result )
    return __readgsqword(0x28u) ^ v6;
  __asm { swapgs }
  return result;
}
/*
内核空间-->用户空间
copy_to_user函数
unsigned long copy_to_user(void *to, const void *from, unsigned long n)
to:目标地址(用户空间)
from:源地址(内核空间)
n:将要拷贝数据的字节数
返回:成功返回0,失败返回没有拷贝成功的数据字节数
*/
signed __int64 __fastcall core_copy_func(signed __int64 my_off)
{
  signed __int64 result; // rax
  __int64 v2; // [rsp+0h] [rbp-50h]
  unsigned __int64 v3; // [rsp+40h] [rbp-10h]
 
  v3 = __readgsqword(0x28u);
  printk(&unk_215);
  if ( my_off > 0x3F )    //检测是否拷贝溢出?
  {
    printk(&unk_2A1);
    result = 0xFFFFFFFFLL;
  }
  else
  {
    result = 0LL;
    qmemcpy(&v2, &name, (unsigned __int16)my_off);//拷贝bss上的全局变量name,长度为my_off,目标栈上参数v2的地址(rbp-50h
//注意这里的my off本来是有符号数字结果被强制转成了无符号数字
  }
  return result;
signed __int64 __fastcall core_copy_func(signed __int64 my_off)
{
  signed __int64 result; // rax
  __int64 v2; // [rsp+0h] [rbp-50h]
  unsigned __int64 v3; // [rsp+40h] [rbp-10h]
 
  v3 = __readgsqword(0x28u);
  printk(&unk_215);
  if ( my_off > 0x3F )    //检测是否拷贝溢出?
  {
    printk(&unk_2A1);
    result = 0xFFFFFFFFLL;
  }
  else
  {
    result = 0LL;
    qmemcpy(&v2, &name, (unsigned __int16)my_off);//拷贝bss上的全局变量name,长度为my_off,目标栈上参数v2的地址(rbp-50h
//注意这里的my off本来是有符号数字结果被强制转成了无符号数字
  }
  return result;
signed __int64 __fastcall core_write(__int64 a1, __int64 a2, unsigned __int64 a3)
{
  unsigned __int64 size; // rbx
 
  size = a3;
  printk(&unk_215);
  if ( size <= 0x800 && !copy_from_user(&name, a2, size) )   // 从用户空间拷贝内容到内核bss段上
    return (unsigned int)size;
  printk(&unk_230);
  return 0xFFFFFFF2LL;
}
signed __int64 __fastcall core_write(__int64 a1, __int64 a2, unsigned __int64 a3)
{

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-10-4 01:30 被Roland_编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 14533
活跃值: (17568)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
mark,感谢分享
2020-10-4 09:46
0
游客
登录 | 注册 方可回帖
返回
//