tls
[TOC] 参考文章
对于tcache
- 修改线程tcache变量
- 在tls区域,有一个线程变量tcache,如果能用largebin attack修改tcache变量,也可以控制tcache的分配。其实这个地方指向的位置本身就是heapbase+0x10,就是tcache_perthread_struct结构从counts开始的地方
- 具体做法:
pwndbg> search -p 0x55555555b010 0x55555555b010这个值实际上是heapbase+0x10
Searching for value: b'\x10\xb0UUUU\x00\x00'
pwn 0x555555558260 0x55555555b010
[anon_7ffff7fc2] 0x7ffff7fc7538 0x55555555b010
pwndbg> hex 0x7ffff7fc7538-0x7ffff7ddc000
+0000 0x1eb538
stack_guard
找的方法和pointer guard一样
pointer guard
- 结构体的类型为struct pthread,我们称其为一个thread descriptor,该结构体的第一个域为tchhead_t类型,其定义如下:
typedef struct
{
void *tcb; /* Pointer to the TCB. Not necessarily the
thread descriptor used by libpthread. */
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
int multiple_threads;
int gscope_flag;
uintptr_t sysinfo;
uintptr_t stack_guard; 0x28
uintptr_t pointer_guard; 0x30
unsigned long int vgetcpu_cache[2];
/* Bit 0: X86_FEATURE_1_IBT.
Bit 1: X86_FEATURE_1_SHSTK.
*/
unsigned int feature_1;
int __glibc_unused1;
/* Reservation of some values for the TM ABI. */
void *__private_tm[4];
/* GCC split stack support. */
void *__private_ss;
/* The lowest address of shadow stack, */
unsigned long long int ssp_base;
/* Must be kept even if it is no longer used by glibc since programs,
like AddressSanitizer, depend on the size of tcbhead_t. */
__128bits __glibc_unused2[8][4] __attribute__ ((aligned (32)));
void *__padding[8];
} tcbhead_t;
- 可以看到这两个宏利用pointer_guard分别对指针进行了加密和解密操作,加密由一次异或以及一次bitwise rotate组成。加密使用的key来自fs:[offsetof(tcbhead_t, pointer_guard)], 利用pointer_guard进行加密的过程可以表示为rol(ptr ^ pointer_guard, 0x11, 64),解密的过程为ror(enc, 0x11, 64) ^ pointer_guard
- 因此我们写入数据的时候用这个加密方式就可以了 eg:
#bin会给数字转化为2进制,但是会带上0b,因此要取[2:]
def ROL(content, key):
tmp = bin(content)[2:].rjust(64, '0')
return int(tmp[key:] + tmp[:key], 2)
ROL(gadget_addr ^ pointer_guard, 0x11)
远程爆破tls
参考此篇博客 在有些情况下,我们需要知道 TLS 的位置以便于修改其中的一些值,例如 canary、tcache struct ptr、key。
但是在大多数情况下,远程的ld.so距离 libc 基址的位置不确定与本地 patchelf 之后的不一致,这时候优先可以考虑起一个 docker 来看看偏移(因为题目大多数都是用 docker 搭建的), 推荐这个项目
如果还是不正确,则说明我们需要爆破偏移,这里的爆破偏移和往常的不同,因为这个偏移值的量在每次连接的时候都是固定的,所以我们只要循环执行足够多的次数,那么就一定能够攻击成功。而且偏移的变化值往往在地址末尾的第四个、第五个数(末三位不变),我们只需要考虑爆破这两个数字即可。
这里提供一个爆破的模版,可以参考一下
for x in range(0x10):
for y in range(0x10):
try:
libc_base = 0x1234
offset = 0x6 << 20
offset += x << 16
offset += y << 12
ld_base = libc_base + offset
log.success("try offset:\t" + hex(offset))
# your code
sh.interactive()
except EOFError:
sh.close()