TLS劫持过canary(TLS Hijack Bypass Canary)
链接:https://pan.baidu.com/s/173QtGe1It9EX2OiocC0ZBw
提取码:1pcz
grxer@grxer ~/D/pwn> checksec checkin |
大致扫了一些,多线程的一个程序
主线程把flag读取到bss段
pthread_create创建的一个子线程的start_routine函数有栈溢出问题,溢出很大
pthread_join()等待阻塞
泄露canary基本不可能了,本来想着SSP(Stack Smashing Protect)Leak能不能把他的argv[0](__libc_argv)覆盖为flag地址,再破坏canary输出flag,但是不在一个线程栈区不一样
线程共享
在一个进程中,主线程和通过pthread_create()创建出来的子线程共享以下内容:
- 进程的代码段、数据段、堆段和共享库等被映射到进程虚拟地址空间中的所有内存区域。
- 进程打开的文件描述符、信号处理器等进程级别的资源。
- 进程环境变量以及命令行参数等。
- 全局变量和静态变量等存储在bss段和data段中的数据。
- 动态分配的堆内存(malloc、calloc等)。
- 在进程中使用pthread_key_create()创建的线程特定数据(Thread-specific data,TSD)。
在Linux中,进程和线程都是轻量级的执行单元,它们有以下区别和联系
区别:
- 资源占用:进程是系统分配资源的基本单位,每个进程拥有独立的地址空间、文件描述符、信号处理器等系统资源,而线程共享同一个进程的资源。
- 调度:进程之间的切换代价比线程之间的切换代价要高,因为进程切换时需要保存和恢复更多的状态信息,而线程只需要保存和恢复少量的状态信息。
- 安全:不同进程之间的内存空间是相互隔离的,因此进程之间的访问不会相互干扰,而线程之间的访问则需要进行同步控制,以避免竞态条件等问题。
联系:
- 资源共享:进程内的所有线程共享同一个地址空间,因此它们可以共享全局变量、静态变量、代码段和数据段等内存区域。
- 处理器调度:线程是处理器调度的基本单位,一个进程中的多个线程可以并发执行,以提高处理器的利用率。
- 通信机制:进程之间通信可以使用IPC机制,而线程之间可以使用线程同步和互斥机制等方式进行通信和协调。
Thread Local Storage
https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html
线程局部存储(TLS),是一种变量的存储方法,每一个线程都会有一个副本,这个变量在它所在的线程内是全局可访问的,但是不能被其他线程访问到,这样就保持了数据的线程独立性。而熟知的全局变量,是所有线程都可以访问的,这样就不可避免需要锁来控制,增加了控制成本和代码复杂度。
gcc里再定义前加__thread就可以实现TLS
创建线程的时候会创建一个TLS(Thread Local Storage),该TLS会存储canary的值,而TLS会保存在stack高地址的地方
主线程中的TLS通常位于mmap映射出来的地址空间里,而位置也比较随机,覆盖的可能性不大;子线程通常也是mmap出来的,子线程中的TLS则位于线程栈的顶部
tcbhead_t结构体
typedef struct |
gdb多线程调试
set follow-fork-mode child
show follow-fork-mode
(1)查看可切换调试的线程:info threads
(2)切换调试的线程:thread 线程id
(3)只运行当前线程:set scheduler-locking on
(4)运行全部的线程:set scheduler-locking off
(5)指定某线程执行某gdb命令:thread apply 线程id gdb_cmd
(6)全部的线程执行某gdb命令:thread apply all gdb_cmd
x/x pthread_self()或fsbase可以查看线程fs基位置
断点断到子线程函数
distance计算偏移,覆盖canary和stack_guard为用一个值即可,rop puts输出flag即可
EXP
from pwn import * |